进程与线程笔记(认真版)

每个线程一个栈,每个进程一个堆,malloc申请的是堆

善用man手册,例如man pthread_cancel

进程

进程的含义

进程能打开文件个数1024;栈的大小8M(8兆)

PCB块:进程控制块 

 系统中只有一个cpu,通过对cpu的调度,作用于每一个pcb,进程控制块(进程所有相关控制信息都在pcb里面放着),实现对每一个程序的运行(并发的)。

并发:可以运行多次

进程和程序的区别

code:代码段(只能被读,不能写)

data:数据段(变量)                                            

heap:堆(开始:malloc,结束:free)

share/map:共享区/映射区(把库函数的函数映射过来)

stack:栈区(8M)(参数,局部变量,返回值都在这里)

linux的进程状态图如图:

进程的作用,状态等 

显示所有进程:

 默认是15也是关闭的意思

kill -9 pid号 强制关闭进程 

fork

一般来说子的pid号略大于父的 

fork简单示例: 

#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();
    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;
}

结果为

CPU的调度是随机的,父和子谁走不一定,但是一定是同时走的 

变量不共享代码:

#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;
}

结果为:

互不影响


 getpid

getpid用法

执行多个程序:子进程

父进程中括号里的pid拿的是子的id号,子进程仅仅代表是子进程并不代表子的id号为0

需要几个子就fork(n)

子认识父,但是父要想认识子只能在第一句里面得到子的id号

getpid和getppid的用法

#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, 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;
    }
    
    printf("a is %d, pid:%d ppid:%d\n",a,getpid(),getppid());
    return 0;
}

 结果为:

(因为变量不共享)

练习:注意截断特性(至少3个,至多8个)

fork()&&fork()||fork()

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

int main(int argc, char *argv[])
{
    
    fork()&&fork()||fork();
    printf("pid :%d\n",getpid());
    return 0;
}

结果为:五个进程,对应五个pid号

父子进程的关系

父子进程代码段是共享的 

通过指针指向code段,因为复制过去其他都要改变,只有code段不变


进程终止的情况

IO的清理工作包括:缓冲区在linux里面,A.out运行完,数据会进入缓冲区,达到一定条件,才能显示到屏幕上,然后关闭文件,关闭流指针。(回收!!!)

exit用法

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    printf("hello");
    exit(0);
    printf("aaaa\n");
    return 0;
}

exit(0);表示程序正常结束

exit(1);表示程序有错误或者exit(-1);

结果为:后面的aaaa没有显示出来,因为exit让进程结束了已经

_exit用法

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    printf("hello");
    _exit(0);
    printf("aaaa\n");
    return 0;
}

 结果为:啥也没打印出来,因为没执行清理函数,不走缓冲区了,缓冲区的数据直接就被扔了,所以啥也不显示

行缓冲是printf后面有\n

全缓冲是fputs对文件的操作

fflush是当前三种都不满足,但还是想在屏幕上看到printf的内容,就写fflush(stdout)

stdout是相对计算机而言的,对于计算机来说就是输出

四个条件只需满足一个就可以

僵尸进程和孤儿进程的定义

进程的退出

 

回收是父进程回收,孤儿进程的时候父都没了,所以不回收,就不管了

organ.c孤儿进程代码:

#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();
    if(pid>0)
    {

        printf("father pid:%d ppid:%d\n",getpid(),getppid());
        exit(0);//正常结束了
    }
    else if(0 == pid)
    {
    
        sleep(3);
        printf("child pid:%d ppid:%d\n",getpid(),getppid());
    }
    else 
    {
        perror("fork");
        return 1;
    }
    
    return 0;
}

结果:

子的ppid(父进程id)已经不是上一行的34807了,因为父已经消亡了

zombie.c 僵尸进程代码:

#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();
    if(pid>0)
    {

        printf("father pid:%d ppid:%d\n",getpid(),getppid());
        sleep(10);
    }
    else if(0 == pid)
    {
    
        printf("child pid:%d ppid:%d\n",getpid(),getppid());
        exit(0);//子消亡
    }
    else 
    {
        perror("fork");
        return 1;
    }
    
    return 0;
}

结果为:

用top命令看

0变1

父结束的时候看看有没有已经结束的子,有的话就将子回收,然后自己再退出

子的pid一般比父大1

作业:创建n个进程 

num_proc.c

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

int main(int argc, char *argv[])
{
    int n =3;
    int i = 0 ;
    for(i=0;i<n;i++)
    {
        pid_t pid = fork();
        if(pid>0)
        {
            continue;
        }
        else if(0 == pid)
        {

                printf("child, pid:%d ppid:%d\n",getpid(),getppid());
                exit(0);
        }
        else 
        {
            perror("fork");
            return 1;
        }
    }
    printf("father pid:%d, ppid:%d\n",getpid(),getppid());
    return 0;
}

结果:一父三子

作业:统计进程的个数

count_process.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
 #include <sys/types.h>
#include <time.h>
#include <dirent.h>
int do_count()
{
    DIR* dir = opendir("/proc");
    if(NULL == dir)
    {
        perror("opendir");
        exit(1);
    }
    int num=0;
    while(1)
    {
        struct dirent* info = readdir(dir);
        if(NULL == info)
        {
            break;
        }

        if(DT_DIR == info->d_type  )//判断它是不是目录
        {
            if(info->d_name[0]>'0' && info->d_name[0]<'9')//判断第一个字符是不是数字
            {
                num++;
            }
        }
        else
        {
            continue;//啥也不是,就读下一个
        }
    
    }
    closedir(dir);
    return num;
}
int main(int argc, char *argv[])
{
    FILE* fp = fopen("1.txt","w");
    if(NULL == fp)
    {
        perror("fopen");
        exit(1);
    }
    time_t tm;
    int n = 3;
    pid_t pid = fork();
    if(pid>0)
    {
        while(n--)
        {
            int num=do_count();
            time(&tm);
            fprintf(fp,"father %d %d %s",getpid(),num,ctime(&tm));
            fflush(fp);
            sleep(3);
        }
    }
    else if(0 == pid)
    {
        while(n--)
        {
            int num=do_count();
            time(&tm);
            fprintf(fp,"child %d %d %s",getpid(),num,ctime(&tm));
            fflush(fp);
            sleep(5);
        }
    }
    else 
    {
        perror("fork");
        return 1;
    }
    fclose(fp);
    return 0;
}

结果:

注意:僵尸进程产生要回收,父对子回收

补充一个不是很重要的函数:回调函数atexit

atexit.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
char * tmp=NULL;
void clean(void)//clean是指针函数,这个是进程退出前来调用的
{
    printf("this is clean %s\n",tmp);
    free(tmp);
}
int main(int argc, char *argv[])
{
    atexit(clean);
    tmp =(char*) malloc(50);//malloc回来的是void*,要强转
    strcpy(tmp,"hello");

    printf("123123\n");

    return 0;
}

进程的回收(针对于僵尸进程)wait 

wait一次只能回收一个,不关心状态括号里写NULL

如果子还没有结束,不能回收,这个时候就进入阻塞状态,父就卡在那不走了,直到有子进程消亡,才能回收

比如说:父同时有两件事,一个是回收,一个是输出,如果阻塞了,那就卡住了,也不会输出也不会回收

wait.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
    pid_t pid = fork();
    if(pid>0)
    {

        printf("father pid:%d ppid:%d\n",getpid(),getppid());
        pid_t recycle_pid = wait(NULL);?//验证wait有阻塞功能
        printf("recycle pid %d\n",recycle_pid);
        sleep(10);
        printf("aaa\n");

    }
    else if(0 == pid)
    {
        sleep(3);    
        printf("child pid:%d ppid:%d\n",getpid(),getppid());
        exit(0);
    }
    else 
    {
        perror("fork");
        return 1;
    }  
    return 0;
}

结果为:

进阶版本

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
    pid_t pid = fork();
    if(pid>0)
    {
        //stat("1.txt",&st);
     
  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值