进程的概念
进程就是执行中的程序,是系统资源分配的最小单位。
进程的内存分配
 
进程的作用
宏观上是并行的,微观上是串行的
进程的状态
对于基本的操作系统:有三个状态: 就绪态->执行态-> 阻塞态
在LInux中有四种:运行态,睡眠态,僵尸态,暂停态。
进程基本的函数
#include <unistd.h>             //fork()函数的头文件
 
fork( )
一次调用,会返回两次。
 子进程先运行和是父进程先进程,顺序不确定。
 变量不共享。
 子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同。(同非常ID号子比父的要大一些)
 功能:通过该函数可以从当前进程中克隆一个同名新进程。
           克隆的进程称为子进程,原有的进程称为 父进程。
           子进程是父进程的完全拷贝。
           子进程的执行过程是从fork函数之后执行。
返回值:
 int 类型的数字
 在父进程中 : 成功   返回值是子进程的pid号 > 0
             失败   返回-1
 在子进程中: 成功    返回值0
                失败   无
 getpid()
 
获得本进程的pid号
getppid()
获得父进程的pid号
父子进程的关系
子进程是父进程的副本。子进程获得父进程数据段,堆,栈,正文段共享。
进程的终止
8个情况
 1)main 中return
 2)exit(), c库函数,会执行io库的清理工作,关闭所有 的流,以及所有打开的文件。已经清理函数(atexit)。
 3)_exit,_Exit 会关闭所有的已经打开的文件,不执行清理函数。
 4) 主线程退出
 5)主线程调用pthread_exit
异常终止
 6)abort()
 7)signal   kill pid
 8)最后一个线程被pthread_cancle
  
注意:
exit(0  /  1 )  在使用的时候都是对的写 0 
                         存在错误的时候写            1
僵尸进程和孤儿进程
僵尸进程:一个主进程用fork创建了子线程,当子线程结束的时候,主线程没有调用wait或者waitpid回收掉这个子进程,这个子进程的任务描述符仍然在系统中。
孤儿进程:一个主进程用fork创建了子线程,主进程已经退出了,而子进程还在继续运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
进程操作示例代码:
1、创建两个线程:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
 #include <sys/types.h>
int main(int argc, char *argv[])
{
    pid_t pid = fork();               //用pid接受fork的返回值判断是父进程还是子进程
    if(pid>0)
    {
        while(1)
        {
            printf("fahter, 发送视频\n");
            sleep(1);
        }
    }
    else if(0 == pid)
    {
    
        while(1)
        {
            printf("child, 接收控制\n");
            sleep(1);
        }
    }
    else 
    {
        perror("fork");
        return 1;
    }
    
    return 0;
} 
2、对父子进程共用代码端的观察
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int a = 10;
int main(int argc, char *argv[])
{
    pid_t pid = fork();
    if(pid>0)
    {
        sleep(3);
        printf("father  a is %d\n",a);
    }
    else if(0 == pid)
    {
        a+=20;
        printf("child  a is %d\n",a);
    }
    else 
    {
        perror("fork");
        return 1;
    }
    
    printf("a is %d\n",a);
    return 0;
}
//输出结果
child a is 30 
a is 30
father a is 10
a is 10
 
由此可知在父子进程中,在fork之前部分的代码为共用,而分进程之后进行的操作各自都会有自己的执行空间。
3、获得自己的pid和父进程的pid
 pid_t pid = fork();
    if(pid>0)
    {
        sleep(3);
        printf("father  a is %d, pid:%d ppid:%d\n",a,getpid(),getppid());
    }
    else if(0 == pid)
    {
        a+=20;
        printf("child  a is %d pid:%d ,ppid:%d\n",a,getpid(),getppid());
    }
    else 
    {
        perror("fork");
        return 1;
    } 
4、atexit //注册终止函数
调用了exit函数使进程终止退出,在进程终止之前,如果注册了终止函数,那么exit函数会先去依次调用进程终止函数,,每调用完一个终止函数并返回,调用顺序是以栈的形式来调用,调用flush刷新IO缓冲区的数据之后返回。
eg:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
char * tmp=NULL;
void clean(void)
{
    printf("this is clean %s\n",tmp);
    free(tmp);
}
int main(int argc, char *argv[])
{
    atexit(clean);
    tmp =(char*) malloc(50);
    strcpy(tmp,"hello");
    printf("123123\n");
    return 0;
} 
输出结果为:
123123
this is clean hello


















