zoukankan      html  css  js  c++  java
  • 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
    ");
        fork();
        printf("hello
    ");
        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
    ");
        }
        else {     /* 父进程运行代码 */
            printf("b
    ");
        }
        /* 父子进程都运行的代码 */
        printf("c
    ");
        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
    ", (long) getpid());
            pause();
            _exit(0);
        } else {
    #if 1 /* define 1 to make child process always a zomie */
            printf("ppid:%d
    ", 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
    ", WEXITSTATUS(status));
    
                if(WIFSIGNALED(status))
                    printf("child process is killed by signal %d
    ", WTERMSIG(status));
    
                if (WIFSTOPPED(status))
                    printf("child process is stopped by signal %d
    ", WSTOPSIG(status));
    
                if (WIFCONTINUED(status))
                    printf("child process resume running....
    ");
    
            } 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等。

  • 相关阅读:
    iOS中的UISearchBar
    iOS中的UIDatePicker 日期选择器
    iOS中的 深拷贝和浅拷贝
    iOS中的定时器实现图片的轮播
    iOS Crash文件的解析(一)
    iOS中的UIToolBar
    iOS中的瀑布流(RootCollectionViewControlle)
    iOS中NSThread(主线程,子线程)
    iOS中的串行,并行,分组,一次,障碍,延迟,反复执行(GCD)
    iOS中的动画
  • 原文地址:https://www.cnblogs.com/westlife-11358/p/10075271.html
Copyright © 2011-2022 走看看