您的位置:首页 > 运维架构 > Linux

Linux进程学习笔记(二、创建进程)

2016-01-25 23:31 573 查看

fork()函数

一个现有的进程可以调用fork函数创建一个新进程

#include <unistd.h>

pid_t fork(void);

//返回值:子进程返回0,父进程返回子进程的ID,若出错,返回-1


子进程对变量所做的改变不影响父进程中该变量的值,即父进程和子进程并不完全共享存储空间。

fork实例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int globvar = 6;
char buf[] = "a write to stdout\n";
int main()
{
int var;
pid_t pid;
var = 88;
if(write(STDOUT_FILENO, buf, sizeof(buf) -1) != sizeof(buf)-1)
printf("write error\n!");
printf("Before fork \n");
if((pid = fork()) < 0)
{
printf("fork error");
}else if(pid == 0){
globvar++;
var++;
}else{
sleep(2);
}
printf("pid = %ld, globvar = %d, var = %d\n", (long)getpid(),globvar,var);
exit(0);
}


运行结果:

a write to stdout
Before fork
pid = 3214, globvar = 7, var = 89
pid = 3213, globvar = 6, var = 88


fork有以下两种用法

(1)父进程希望复制自己,使父进程和子进程同时执行不同的代码段。常用于网络服务进程中–父进程等待客户端的服务请求。

(2)一个进程要执行一个不同的程序。在shell中常见,fork返回后立即调用exec

vfork函数()

vfork函数的调用序列和返回值与fork相同,但两者语义不同。

vfork函数用于创建一个新进程,该新进程的目的是exec一个新程序

vfork与fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec。

vfork与fork另一个区别是:vfork保证子进程先运行,在它调用exec或exit后父进程才可能被调度运行。

vfork实例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int globvar = 6;
int main(void)
{
int var;
pid_t pid;

var = 88;
printf("before fork\n");
if((pid = vfork()) < 0)
{
printf("vfork error");
}else if(pid == 0)
{
globvar++;
var++;
_exit(0);
}
printf("pid = %ld, globvar = %d, var = %d\n", (long)getpid(), globvar, var);

exit(0);
}


运行结果:

before fork
pid = 3329, globvar = 7, var = 89


改变了父进程的值,因为子进程在调用exit或exec之前是在父进程空间运行的。

system()函数

函数原型:

#include <stdlib.h>
int system(const char *cmdstring);

//返回值:若cmdstring是空指针,返回非零值


因为system在实现中调用了fork,exec,和waitpid,因此有三种返回值

(1)fork失败或者waitpid返回除EINTR之外的出错,则system返回-1,并且设置errno以指示错误类型。

(2)如果exec失败,则其返回值如同shell执行了exit(127)一样(命令未找到)

(3)fork,exec,和waitpid都成功,那么system返回值是shell终止状态。

使用system而不是直接使用fork和exec的优点是:system进行了所需的各种出错处理以及各种信号处理

exec函数()

调用exec函数时,该进程执行的程序完全替换为新程序,而新程序从其main函数开始执行。

因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆段、栈段。

execl函数原型:

#include <unistd.h>
int execl(const char *pathname, const char *arg0, ...);

// 返回值:出错返回-1 成功不返回。


使用execl函数创建进程 实例

int execl(const char *path, const char *arg,...);


先创建
sum.c


#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int sum;
if(argc != 3)
{
printf("args error\n");
return -1;
}
sum = atoi(argv[1]) + atoi(argv[2]);
printf("sum = %d\n", sum);
return 0;
}


gcc -o sum sum.c


生成sum

创建
exec.c


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
printf("start now \n");
execl("./sum","sum", "41", "34", NULL);
printf("我是不会被执行的!\n");
return 0;
}


gcc -o exec exec.c


生成
exec
,执行
exec


yu@ubuntu:~/0125/fork$ ./exec
start now
sum = 75


printf("我是不会被执行的!\n");
此句不会执行。

popen函数和pclose函数

函数原型:

#include <stdio.h>

FILE *popen(const char *comstring, const char *type);

//返回值:成功返回文件指针;出错返回NULL

int pclose(FILE *stream);

//返回值:若成功,返回cmdstring的终止状态;出错返回-1


使用管道工作

这两个函数实现的操作是:创建一个管道,fork一个子进程,关闭未使用的管道端,执行一个shell命令,然后等待命令终止。

执行过程

popen先执行fork,然后调用exec执行cmdstring,返回一个标准I/O文件指针

如果type是“r”,文件指针连接到cmdstring的标准输入

如果type是“w”,则文件指针连接到cmdstring的标准输入

//执行fp = popen(cmdstring, "r");

//父进程fp<--------------子进程cmdstring(stdout)


//执行fp = popen(cmdstring, "w");

//父进程fp-------------->子进程cmdstring(stdin)


pclose函数关闭标准I/O流,等待命令终止,然后返回shell的终止状态。

popen()函数用创建管道的方式启动一个进程, 并调用 shell. 因为管道是被定义成单向的,所以type参数只能定义成只读或者只写,不能是两者同时, 结果流也相应的是只读或者只写.

pclose等待新进程的结束,而不是杀新进程。

popen创建进程实例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fp;
fp = popen("ls -l", "r");
if(NULL == fp)
{
perror("popen");
return -1;
}
char buf[512];
bzero(buf,sizeof(buf));
int ret = fread(buf, 1, 512, fp);
if(ret > 0)
{
printf("%s\n", buf);
}
return 0;
}


gcc -o popen popen.c


./popen


运行结果

yu@ubuntu:~/0125/fork$ ./popen
total 56
-rwxrwxr-x 1 yu yu 7544 Jan 25 05:23 a.out
-rwxrwxr-x 1 yu yu 7364 Jan 25 06:22 exec
-rw-rw-r-- 1 yu yu  196 Jan 25 06:22 exec.c
-rw-rw-r-- 1 yu yu  510 Jan 25 04:55 fork.c
-rwxrwxr-x 1 yu yu 7528 Jan 25 07:05 popen
-rw-rw-r-- 1 yu yu  349 Jan 25 07:05 popen.c
-rwxrwxr-x 1 yu yu 7400 Jan 25 06:20 sum
-rw-rw-r-- 1 yu yu  230 Jan 25 06:20 sum.c
-rw-rw-r-- 1 yu yu  112 Jan 25 04:55 temp.out
-rw-rw-r-- 1 yu yu  418 Jan 25 05:22 vfork.c
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: