获取当前进程的id号
#include <sys/types.h>
#include <unistd.h>pid_t getpid(void);
pid_t getppid(void);
我们每写一份代码,它运行之后都是处于进程中的,我们可以用getpid()函数来读取当前代码的进程id号 。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = getpid();
printf("cur pid is %d\n",pid);
return 0;
}
运行之后的效果。
CLC@Embed_Learn:~/test_11.5$ gcc test1.c
CLC@Embed_Learn:~/test_11.5$ ./a.out
cur pid is 16384
CLC@Embed_Learn:~/test_11.5$ ./a.out
cur pid is 16385
CLC@Embed_Learn:~/test_11.5$ ./a.out
cur pid is 16386
CLC@Embed_Learn:~/test_11.5$ ./a.out
cur pid is 16388
CLC@Embed_Learn:~/test_11.5$
我们可以通过getpid函数读取当前进程的id号,但是同一个代码每次运行起来后,它的id号是不一样的。
创建进程
#include <unistd.h>
pid_t fork(void);
创建进程非常简单,只需要一个fork()函数就好了。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("123\n");
fork();
printf("hello world\n");
return 0;
}
我们main函数进去第一句打印一个123,然后fork()创建一个进程后,打印hello world,看看会是什么效果。
CLC@Embed_Learn:~/test_11.5$ gcc test2.c
CLC@Embed_Learn:~/test_11.5$ ./a.out
123
hello world
hello world
CLC@Embed_Learn:~/test_11.5$
我们可以看到,123打印了一次,hello world打印了2次。为什么hello world会打印两次,是因为fork()函数创建了一个子进程,子进程又打印了一次。因为我们的123在fork()函数之前打印了,所以子进程并不会一起打印123。
由此我们可以,子进程会执行父进程fork()后的所有代码。父进程指的是当前进程的进程,子进程是指父进程创建的进程,也可以理解为fork()函数创建的进程。
区分父子进程
我们如何分辨父子进程呢,可以通过getpid()函数来读取他们的进程号。如果fork()函数之前的id等于fork()之后的id就是父进程,不想等就是子进程。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid1;
pid_t pid2;
pid1 = getpid();
fork();
pid2 = getpid();
if(pid1 == pid2)
{
printf("this is father pid1 = %d pid2 = %d\n",pid1,pid2);
}
else
{
printf("this is child pid1 = %d pid2 = %d\n",pid1,pid2);
}
return 0;
}
首先,父进程第一次执行代码, pid1的值和pid2的值是一致的,父进程不会因为通过fork()函数创建了子进程而立刻读取子进程的id号。父进程会先执行完整个代码的流程,然后创建子进程去读取子进程的id号。
CLC@Embed_Learn:~/test_11.5$ gcc test3.c
CLC@Embed_Learn:~/test_11.5$ ./a.out
this is father pid1 = 16838 pid2 = 16838
this is child pid1 = 16838 pid2 = 16839
因为我们之前说过,在fork()函数之前执行的代码,子进程不会执行。所以pid1的id是父进程的id,我们可以看到当pid1与pid2相等时,他就是父进程,不相等时就是子进程。
除此我们还可以读取fork()函数的返回值来区分父子进程。fork()的返回值为非负数时,为父进程,等于0时为子进程。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
if(pid > 0)
{
printf("this is father getpid is %d , fork id is %d\n",getpid(),pid);
}
else if(pid == 0)
{
printf("this is child getpid is %d , fork id is %d\n",getpid(),pid);
}
return 0;
}
看一下运行效果。
CLC@Embed_Learn:~/test_11.5$ gcc test5.c
CLC@Embed_Learn:~/test_11.5$ ./a.out
this is father getpid is 17097 , fork id is 17098
this is child getpid is 17098 , fork id is 0
一目了然。
vfork创建进程
#include <sys/types.h>
#include <unistd.h>pid_t vfork(void);
vfork()和fork()的区别在于,在while(1)循环中,vfork()函数会等待子进程结束在运行父进程,而fork()的父子进程会一起运行。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
pid = fork();
if(pid > 0)
{
while(1)
{
printf("this is father pid %d\n",getpid());
sleep(1);
}
}
else if(pid == 0)
{
while(1)
{
printf("this is child pid %d\n",getpid());
sleep(1);
}
}
return 0;
}
看一下效果。
CLC@Embed_Learn:~/test_11.5$ gcc test6.c
CLC@Embed_Learn:~/test_11.5$ ./a.out
this is father pid 17242
this is child pid 17243
this is father pid 17242
this is child pid 17243
this is father pid 17242
this is child pid 17243
this is father pid 17242
this is child pid 17243
this is father pid 17242
this is child pid 17243
this is child pid 17243
this is father pid 17242
this is father pid 17242
this is child pid 17243
this is father pid 17242
this is child pid 17243
this is child pid 17243
this is father pid 17242
我们可以看到,父进程和子进程是一起运行的,那么用vfork()函数试试。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = vfork();
if(pid > 0)
{
while(1)
{
printf("this is father pid %d\n",getpid());
sleep(1);
}
}
else if(pid == 0)
{
while(1)
{
cnt ++;
printf("this is child pid %d\n",getpid());
sleep(1);
if(cnt == 5)
{
exit(-1);
}
}
}
return 0;
}
定义了一个cnt用来计数,当子进程执行5次后退出,看看效果。
CLC@Embed_Learn:~/test_11.5$ gcc test7.c
CLC@Embed_Learn:~/test_11.5$ ./a.out
this is child pid 17346
this is child pid 17346
this is child pid 17346
this is child pid 17346
this is child pid 17346
this is father pid 17345
this is father pid 17345
this is father pid 17345
this is father pid 17345
我们可以看到先是执行了5次子进程,子进程结束后再执行父进程。
wait函数的使用
#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
vfork()函数可以让子进程运行后再运行父进程,那么fork()函数可不可以呢,答案是肯定的。wait()函数的用处就是用来等待子进程的退出,并且读取退出码。
在上面的例子中,我们子进程用exit(-1)来退出,-1就是子进程的退出码。那么怎么等待,怎么读取呢?
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = fork();
if(pid > 0)
{
while(1)
{
wait(NULL);
printf("this is father pid %d\n",getpid());
sleep(1);
}
}
else if(pid == 0)
{
while(1)
{
cnt ++;
printf("this is child pid %d\n",getpid());
sleep(1);
if(cnt == 5)
{
exit(-1);
}
}
}
return 0;
}
我们并没有对代码进行过多的修改,只是把vfork()函数改成fork(),并且在父进程的while(1)循环里加上一个wait()函数。wait()函数的参数我们给的是NULL,代表的是我们只是单纯的等待子进程退出,并不关心它的退出码。
CLC@Embed_Learn:~/test_11.5$ gcc test8.c
CLC@Embed_Learn:~/test_11.5$ ./a.out
this is child pid 17522
this is child pid 17522
this is child pid 17522
this is child pid 17522
this is child pid 17522
this is father pid 17521
this is father pid 17521
this is father pid 17521
this is father pid 17521
this is father pid 17521
效果和vfork()函数一样。那么如何读取子进程的退出码呢?
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
int status;
int cnt = 0;
pid = fork();
if(pid > 0)
{
while(1)
{
wait(&status);
printf("status is %d\n",WEXITSTATUS(status));
printf("this is father pid %d\n",getpid());
sleep(1);
}
}
else if(pid == 0)
{
while(1)
{
cnt ++;
printf("this is child pid %d\n",getpid());
sleep(1);
if(cnt == 5)
{
exit(3);
}
}
}
return 0;
}
首先定义一个变量status来接收状态码,然后取status的地址放入wait()函数中,然后把他打印出来。打印我们要加上WEXITSTATUS这个宏才有效。
CLC@Embed_Learn:~/test_11.5$ gcc test9.c
CLC@Embed_Learn:~/test_11.5$ ./a.out
this is child pid 17631
this is child pid 17631
this is child pid 17631
this is child pid 17631
this is child pid 17631
status is 3
this is father pid 17630
status is 3
this is father pid 17630
status is 3
this is father pid 17630
status is 3
this is father pid 17630
读到的退出码和我们写的退出码一致。