Multi-process programming language C

First, the process Introduction

1, the process of the implementation of the program. Program is static, the process is dynamic.
2, the process consists of three parts in the memory: the data segment, a stack segment and code segment.
Code segment : data is stored program code, if several processes running the same program, then they can use the same code segment (code segments can be shared);
stack segment : is stored in the subroutine return address, local variables and parameters of the program, mainly to save the process execution environment, where the characteristics of the advanced use of the stack, the memory can be seen as environmentally last executed.
Data segments : program store global variables, constants
3, dynamic allocation of data space data
system if the same run several programs simultaneously, they can not use the same between a stack and data segments, it may be used the same code segment ( code segment can be shared)
. 4, LWP:
thread ID. Command used in the user state (such as ps) display mode.

Second, create a process fork ()

1, header files

#include<unistd.h>  
#include<sys/types.h>  

2, the function prototype

pid_t fork( void);

pid_t is a macro definition

3, the return value

If successful call once the two values ​​is returned, the child returns 0, the parent returns the child process ID; otherwise, an error return -1

4, Notes

a, in the process of creating a Linux system in two ways: First, created by the operating system, the second is to create a process by the parent process (usually the child). System calls fork () creates a new process is the only way, of course vfork () can also create a process, but in fact it still calls the fork () function. fork () function is a special Linux system function, its first call will have two return values.

b, after calling fork (), the order of execution of the parent process and the child process is that we can not be determined (ie the scheduling process using CPU), realize this is extremely important, because in some poorly designed programs can lead to competition for resources, so unpredictable problems.

c, performance fork child process is that it produces will return twice, once returns 0, execute the following code sequence. This is the child process. Pid returned once the child process, but also the order of execution of the following code, which is the parent process.

After d, the process is successfully created, the parent process and the child process begins execution after fork (), but with different pid. fork can be seen as the program statement as cut A, two parts B. (After the fork () succeeds, the child process the parent process to get all the variables, environment variables, and the current value of the program counter space).

e, in general, after the fork () succeeds, the execution order of the parent process and the child process is uncertain. It depends on the scheduling algorithm used by the kernel, if his son process requires synchronization with each other, require some form of inter-process communication.

5, vfork () function

Also used to create a process, the return value and fork () the same.
fork () and vfork () Differences between
execution order:
A, fork (): scheduling chamber parent and child processes is determined by the scheduler;
B, vfork (): Exit is to call sub-process, and other sub-processes (1) after the call, then call the parent process;
impact on the data segment:
a, fork (): parent and child do not share some address space, modify the child process, the contents of the parent process will not be affected.
b, vfork ():, it runs in the space of the parent process before the child process calls exit, that is to say will change the parent process's data segment, stack and heap. . That share code and data areas, and the address and the contents are the same.

Third, for example

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <vector>
#include <iostream>
#include<sys/wait.h>

using namespace std;

// 进程退出函数
void print_exit()  
{  
       printf("the exit pid:[%d] \n",getpid() );  
} 

int main()
{
    string sMatch;
    pid_t pid, child_pid;
    vector<string> provList;
    provList.push_back("taskFace");
    provList.push_back("taskObj");
    provList.push_back("taskAction");
    provList.push_back("taskHat");
    provList.push_back("taskOther");

    cout << "Main process,id=" << getpid() << endl;

    // 循环处理"100,200,300,400,500"
    for (vector<string>::iterator it = provList.begin(); it != provList.end(); ++it)
    {
        sMatch = *it;
        atexit( print_exit );
        pid = fork();
        // (*hsq*)子进程退出循环,不再创建子进程,全部由主进程创建子进程,这里是关键所在
        if(pid == 0 || pid == -1)
        {
            break;
        }
    }

    if(pid == -1)
    {
        cout<<"Fail to fork!"<<endl;
        exit(1);
    }
    else if(pid == 0)
    {
        // 这里写子进程处理逻辑
        cout <<"This is children process,id=" << getpid() << ",start to process " << sMatch << endl;
        sleep(10);
        exit(0);
    }
    else
    {
        // 这里主进程处理逻辑
        cout << "This is main process,id=" << getpid() <<",end to process "<< sMatch << endl;

        do 
        {   
            // WNOHANG 非阻塞 轮询 等待带子进程结束
            child_pid = waitpid(pid, NULL, WNOHANG);  
            printf("I am main progress.The pid progress has not exited!\n");
            sleep(2);

        }while(child_pid == 0);
        exit(0);
    }

    return 0;
}

Fourth, the code analysis

执行结果如下:
Main process,id=6803
This is children process,id=6804,start to process taskFace
This is children process,id=6805,start to process taskObj
This is main process,id=6803,end to process taskOther
This is children process,id=6806,start to process taskAction
I am main progress.The pid progress has not exited!
This is children process,id=6807,start to process taskHat
This is children process,id=6808,start to process taskOther
I am main progress.The pid progress has not exited!
I am main progress.The pid progress has not exited!
I am main progress.The pid progress has not exited!
I am main progress.The pid progress has not exited!
the exit pid:[6804] 
the exit pid:[6806] 
the exit pid:[6805] 
the exit pid:[6806] 
the exit pid:[6806] 
the exit pid:[6805] 
the exit pid:[6807] 
the exit pid:[6807] 
the exit pid:[6807] 
the exit pid:[6807] 
the exit pid:[6808] 
the exit pid:[6808] 
the exit pid:[6808] 
the exit pid:[6808] 
the exit pid:[6808] 
I am main progress.The pid progress has not exited!
the exit pid:[6803] 
the exit pid:[6803] 
the exit pid:[6803] 
the exit pid:[6803] 
the exit pid:[6803] 

As can be seen from the results, the child function in
6804: out of the first
6805: Exit twice
6806: out of the three
6807: out of the four
6808: out of the five
main process
6803 out of the five

The following explains about the main reason for this problem occurs:
1. Why is there
6804: Exit a
6805: Exit twice
6806: out of the three
6807: out of the four
6808: out of the five
phenomena
A: Because most the following is the equivalent of 6808 fork five times, each subsequent child process out of the process of the discovery process id already exists, it will not be repeated to create a new process, so each child process task is executed only once, but quit when they quit 5 times.
2, the main process Why quit five times
at The Exit pid: [6803]
at The Exit pid: [6803]
at The Exit pid: [6803]
at The Exit pid: [6803]
at The Exit pid: [6803]
A: Each child processes open a new master and child processes. So there will be five main process exits phenomenon. The main process will not attach labels, but the child will be attached to each fork label
Here Insert Picture Description

Fifth, the process to begin execution of the position of father and son

#include <unistd.h> 
#include <sys/types.h>
main () 
{ 
         pid_t pid; 
         printf("hello!\n");  
         pid=fork();
         if (pid < 0) 
                 printf("error in fork!"); 
         else if (pid == 0) 
                 printf("i am the child process, my process id is %d\n ",getpid());
         else 
                 printf("i am the parent process, my process id is %d\n",getpid());
         printf("bye!\n");
} 

Here you can see the parent process implemented printf ( "hello \ n!" ); And the child process is not performed printf ( "hello \ n!" );
A people very confusing example:

#include <unistd.h>
#include <sys/types.h>
main () 
{ 
         pid_t pid; 
         printf("fork!");    //printf("fork!\n")
         pid=fork(); 

         if (pid < 0) 
                 printf("error in fork!\n"); 
         else if (pid == 0) 
                 printf("i am the child process, my process id is %d\n",getpid());
         else 
                 printf("i am the parent process, my process id is %d\n",getpid());
}

At this time, the printout of the two fork! This can not help but think that is a child process begins execution #include place, so also performed printf ( "fork!"); Statement.
The reason is not the case, this problem is that:
This is related with the buffering mechanism Printf, printf when certain content, the operating system is just the content on the stdout buffer queue, and no actual writes to the screen on. However, after they see there is \ n, it will immediately refresh stdout, and therefore immediately able to print the .mian function (parent process) run printf ( "fork!"), "Fork!" Only to be placed in the buffer, when you run the fork, inside the buffer AAAAAA child process (child process) inherited, so the extent of child stdout buffer into which it has also been a "fork!". So, you will eventually see a "fork!" Was 2 times !!! printf function and mian (parent process) run printf ( "fork! \ N" ) after, "fork!" Is printed immediately to the screen and then fork to the child process (child process) in the buffer stdout not expect a "fork!" So you see the contents of the result will be "fork!" is a printf once !!!

Published 297 original articles · won praise 6 · views 8529

Guess you like

Origin blog.csdn.net/qq_23929673/article/details/98885118