进程基础

进程基础知识

1、进程标识符pid

pid_t (int16_t),有可能不够用 。
命令ps,  ps -axf
**进程号是顺次向下使用。(与fd有区别)**
获取当前进程的pid:getpid(); 	
获取父进程的pid:getppid();

2、进程的产生 fork();

①duplicating的,复制,拷贝,一模一样,连运行到的位置都相同
fork后父子进程的区别fork的返回值不一样,pid不同,ppid也不同,
未决信号(还没来得及去响应的信号)和文件锁不继承,资源利用量归零。

③Init进程:1号,是所有进程的祖先进程。
④fork成功,父进程中返回的是子进程的Pid,子进程中返回0;fork失败,父进程中返回-1,设置errno。

永远不要猜测父子进程哪先被调度,这是由调度器的调试策略决定的。

了解:vfork();

用vfork创建的子进程,实际和父进程指向的是同一块物理内存;但vfork创建的子进程,只能调用_exit()或exec(),其它行为(如关闭一个文件)是未定义的。

fork()是写时拷贝,只读时父子进程指向同一块空间。父子进程谁想写,谁去复制一份内存到其它空间。fork通过写时拷贝技术,基本将过去vfork的功能糅合进来了,所以vfork逐渐被废弃


fork函数例程

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

int main()
{
    pid_t pid;

    printf("[%d]:begin.\n",getpid());
    //加了\n,因为默认输出设备是stdout,行缓冲,会刷新缓冲区;
    //所以命令./fork,打印一次begin

    //命令./fork1 > /tmp/out,还来得及没写到文件(全缓冲)中,马上fork了,
    //使得父子进程缓冲区都有存在一句“begin.”。    

    fflush(NULL);//正确的做法是fork之前刷新所有打开的流。

    pid = fork();
    if(pid < 0)
    {
        perror("fork()");
        exit(1);
    }

    if(pid == 0)    //child
    {
        printf("[%d]:child is working\n",getpid());
    }
    else            //parent
    {
        printf("[%d]:parent is working\n",getpid());
    }

    printf("[%d]:end.\n",getpid());

    exit(0);
}

打印结果,与缓冲区有关。比较下列三种结果:
①终端输出,行缓冲
进程基础
②fork前使用fflush刷新缓冲区
进程基础
③fork前不调用fflush:
进程基础

3、进程的消亡及释放资源

使用wait或waitpid函数等待进程状态发生变化

①函数原型:pid_t wait(int *status);
成功返回终止子进程的pid,将子进程的状态存储到status指向的内存。死等,是阻塞的。

②函数原型:pid_t waitpid(pid_t pid, int *status, int options);

options是位图,如果有WNOHANG参数,函数变成非阻塞的。
pid: <-1,收进程组id为|-n|中的任何一个子进程
  -1,收任何一个子进程
  0,收与当前进程同组的一个子进程
  >0,收指定pid号的子进程

wait(&status) 相当于 waitpid(-1,&status,0)
如果只是要回收而不关心子进程的状态,也可以wait(NULL)。

多进程编程:

找出某区间内的所有质数

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

#define LEFT    30000000
#define RIGHT   30000200
int main()
{
    int i,j,mark;
    pid_t pid;

    for(i = LEFT; i <= RIGHT; i++)
    {
        //父进程不断创建子进程
        pid = fork();
        if(pid < 0)
        {
            perror("fork()");
            exit(1);
        }

        //质数的计算交给子进程
        if(pid == 0)        //child
        {
            mark = 1;
            for(j = 2; j < i/2; j++)
            {
                if(i % j == 0)
                {
                    mark = 0;
                    break;
                }
            }
            if(mark)
                printf("%d is primer\n",i);

            //如果没有exit,子进程还会去fork。
            exit(0);//子进程正常终止
        }
    }
    
    for(i = LEFT; i <= RIGHT; i++)
        wait(NULL);//只是要回收,不关心回收的子进程的状态

    exit(0);
}


/***************没必要每次计算都创建进程,可以创建N个进程交叉分配计算任务,作出如下优化***********************/

int main()
{
    int i,j,n,mark;
    pid_t pid;

    for(n = 0; n < N; n++)
    {
        pid = fork();
        if(pid < 0)
        {
            perror("fork()");
            exit(1);
        }

        //父进程连续创建N个子进程后等待N个子进程完成计算,子进程交叉分配任务

        if(pid == 0)	//child
        {
            //第一个进程分配的数总是3的倍数
            for(i = LEFT + n; i <= RIGHT; i += N)
            {
                    mark = 1;
                    for(j = 2; j < i/2; j++)
                    {
                        if(i % j == 0)
                        {
                            mark = 0;
                            break;
                        }
                    }
                    if(mark)
                        printf("[%d]:%d is primer\n",n,i);

            }
             exit(0);//子进程正常终止
         }
    }

    for(n = 0; n < N; n++)
        wait(NULL);//只是要回收,不关心回收的子进程的状态

    exit(0);
}

上一篇:linux c++(进程相关的函数 & 第一篇 fork)


下一篇:github fork PR 的简单使用