Linux进程、线程、任务调度(1)贵在坚持

1:PCB进程控制块

Task_struct结构体,也就是PCB,存放着这个进程所需要的所有资源的结构的描述。

PCB管理:链表、树、哈希。

2:进程生命周期

六种状态:就绪态、运行态、停止态、深度睡眠态、浅睡眠态、僵尸态。

前三个好理解,主要是后三个:

深睡眠:进程处于睡眠态(调用sleep),等到资源到位,就可以被调度(变成就绪态TASK_RUNNING)。

浅睡眠:进程处于睡眠态(调用sleep),等到资源到位,或者收到信号,就可以被调度(变成就绪态TASK_RUNNING)。

僵尸态:父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。子进程的状态变成EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息。在 wait 调用之后,僵尸进程就完全从内存中移除。因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中。

正常的进程睡眠都是浅睡眠,但是内核中有一些进程处于睡眠态不希望被信号打断,那么它就会处于深睡眠状态。

3:folk创建子进程

举个例子:

int main() {
    fork();
    printf("hello\n");
    fork();
    printf("hello\n");
    while (1);
    return 0;
}

打印几个hello?

一分为2,打印2次;2分为4,打印4次;一共6次。

fork()函数的返回值是返回两次的,在父进程中返回子进程的pid,在子进程中返回0。利用分支识别:

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

int main(){
    pid_t pid;

    pid = fork();

    if(pid==-1){ /* 创建不成功 */
        perror("Can't creat new process");
        exit(1);
    }
    else if(pid==0){  /* pid==0,子进程运行代码 */
        printf("a\n");
    }
    else {     /* 父进程运行代码 */
        printf("b\n");
    }
    /* 父子进程都运行的代码 */
    printf("c\n");
    while(1);
}

Linux中编译执行:gcc 1.c -o 1

再:./1

结果:

b

c

a

c

分析:

父进程返回子进程pid(不为0)输出b,再输出c。

子进程返回0,输出a,再输出c。

4:子死父清场

例如:

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

int main(void)
{
    pid_t pid,wait_pid;
    int status;

    pid = fork();

    if (pid==-1)    {
        perror("Cannot create new process");
        exit(1);
    } else     if (pid==0) {
        printf("child process id: %ld\n", (long) getpid());
        pause();
        _exit(0);
    } else {
#if 1 /* define 1 to make child process always a zomie */
        printf("ppid:%d\n", getpid());
        while(1);
#endif
        do {
            wait_pid=waitpid(pid, &status, WUNTRACED | WCONTINUED);

            if (wait_pid == -1) {
                perror("cannot using waitpid function");
                exit(1);
            }

            if (WIFEXITED(status))
                printf("child process exites, status=%d\n", WEXITSTATUS(status));

            if(WIFSIGNALED(status))
                printf("child process is killed by signal %d\n", WTERMSIG(status));

            if (WIFSTOPPED(status))
                printf("child process is stopped by signal %d\n", WSTOPSIG(status));

            if (WIFCONTINUED(status))
                printf("child process resume running....\n");

        } while (!WIFEXITED(status) && !WIFSIGNALED(status));

        exit(0);
    }
}

照样gcc 2.c -o 2

./2

输出:

ppid:5715

child process id: 5716

(别结束运行)

在另一终端查看父子进程:命令ps -lA

找到父子进程状态:

然后:

kill -9 5716

再查看状态:

子进程转为僵尸态了。

 以上是在#if 1 的情况下

如果修改为 #if 0

那么再次编译运行   结果是:

child process id: 5901

(也别结束运行)

再另一个终端查看父子进程

kill子进程,发现运行的2程序结束运行了,且报告了原因

可以看出父进程可以通过waitpid()函数回收子进程的task_struct结构。

5:总结

这张六种状态图蛮重要,记录下来。

 

 我是小狼程序员,希望在自己在计算机方面的知识懂的越来越多,技术越来越熟练。

欢迎大家加我qq交流:809291807

目前交流方向可以有:数据结构与算法、计算机操作系统、C++编程、Java编程、Linux等。

 

转载于:https://www.cnblogs.com/westlife-11358/p/10075271.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值