Linux下C语言开发-多进程开发

文章目录

大家都知道,为了提高程序运行效率,充分利用计算机资源,一般会选用多进程或者多线程的方式进行程序开发。今天本文来介绍下如何进行基于多进程开发。

进程的基础知识

1、进程可以看做程序的一次执行过程。在linux下,每个进程有唯一的PID标识进程。PID是一个从1到32768的正整数,其中1一般是特殊进程init,其它进程从2开始依次编号。当用完32768后,从2重新开始。

2、linux中有一个叫进程表的结构用来存储当前正在运行的进程。可以使用“ps aux”命令查看所有正在运行的进程。

3、进程在linux中呈树状结构,init为根节点,其它进程均有父进程,某进程的父进程就是启动这个进程的进程,这个进程叫做父进程的子进程。

fork的基础知识

fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。

2009121121573496

上图表示一个含有fork的程序,而fork语句可以看成将程序切为A、B两个部分。

然后整个程序会如下运行:

step1、设由shell直接执行程序,生成了进程P。P执行完Part. A的所有代码。

step2、当执行到pid = fork();时,P启动一个进程Q,Q是P的子进程,和P是同一个程序的进程。Q继承P的所有变量、环境变量、程序计数器的当前值。

step3、在P进程中,fork()将Q的PID返回给变量pid,并继续执行Part. B的代码。

step4、在进程Q中,将0赋给pid,并继续执行Part. B的代码。

这里有三个点非常关键:

1、P执行了所有程序,而Q只执行了Part. B,即fork()后面的程序。(这是因为Q继承了P的PC-程序计数器)

2、Q继承了fork()语句执行时当前的环境,而不是程序的初始环境。

3、P中fork()语句启动子进程Q,并将Q的PID返回,而Q中的fork()语句不启动新进程,仅将0返回。

进程的创建

进程的创建十分简单,仅需要fork()函数即可。但是需要注意的是,子进程与父进程之间除了代码是共享的之外,堆栈数据和全局数据均是独立的。

参考示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <unistd.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <math.h>  
#include <errno.h>  
#include <sys/types.h>  
#include <sys/wait.h>  
 
int main()  
{  
    pid_t pid;  
 
    if(-1 == (pid = fork())) {  
        printf("Error happened in fork function!\n");  
        return 0;  
    }  
 
    if(0 == pid) {  
        printf("This is child process: %d\n", getpid());  
    } else {  
        printf("This is parent process: %d\n", getpid());  
    }  
 
    return 0;  
}

fork出错可能有两种原因:

1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。

2)系统内存不足,这时errno的值被设置为ENOMEM。

进程的等待

所谓进程等待,其实很简单。前面我们说过可以用fork创建子进程,那么这里我们就可以使用wait函数让父进程等待子进程运行结束后才开始运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int main(int argc, char* argv[])
{
    pid_t pid;
 
    pid = fork();
    if(0 == pid) {
        printf("This is child process, %d\n", getpid());
        sleep(5);
    } else {
        wait(NULL);
        printf("This is parent process, %d\n", getpid());
    }
 
    return 0;
}

进行编译,输入gcc fork.c -o fork, 然后输入./fork,就会在console下面获得这样的结果

1
2
3
[root@localhost fork]# ./fork
This is child process, 2135
This is parent process, 2134

进程间通信

Linux系统本身为进程间通信提供了很多的方式,比如说管道、共享内存、socket通信等。管道的使用十分简单,在创建了匿名管道之后,我们只需要从一个管道发送数据,再从另外一个管道接受数据即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>  
#include <unistd.h>  
#include <stdlib.h>  
#include <string.h>  
 
int pipe_default[2];    
 
int main()  
{  
    pid_t pid;  
    char buffer[32];  
 
    memset(buffer, 0, 32);  
    if(pipe(pipe_default) < 0) {  
        printf("Failed to create pipe!\n");  
        return -1;  
    }  
 
    if(0 == (pid = fork())) {  
        close(pipe_default[1]);  
        sleep(5);  
        if(read(pipe_default[0], buffer, 32) > 0) {  
            printf("Receive data from server, %s!\n", buffer);  
        }  
        close(pipe_default[0]);  
    } else {  
        close(pipe_default[0]);  
        if(-1 != write(pipe_default[1], "hello", strlen("hello"))) {  
            printf("Send data to client, hello!\n");  
        }  
        close(pipe_default[1]);  
        waitpid(pid, NULL, 0);  
    }  
 
    return 0;  
}

进行编译,输入gcc pipe.c -o pipe,然后输入./pipe,过一会儿你就可以看到下面的打印了

1
2
3
[test@localhost pipe]$ ./pipe  
Send data to client, hello!  
Receive data from server, hello!

参考文章:
linux下的C语言开发(进程创建)
linux下的C语言开发(进程等待)
linux下的C语言开发(管道通信)
从一道面试题谈linux下fork的运行机制
Linux中fork函数分析



本文出自 TENNFY WU,转载时请注明出处及相应链接。

本文永久链接: http://www.tennfy.com/4703.html

下一篇文章:

上一篇文章:

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

6 + 6 = ?


您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

返回顶部