12.线程(一)

一.SIGCHLD信号补充

应该子进程退出的时候,系统默认对其的信号是Ign的,所以我们看不到对应的反应

#include <iostream>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> // 注意:原代码中使用了sleep函数,需包含此头文件
#include <wait.h>


void handler(int signo)
{
    std::cout << "get a sig: " << signo << std::endl;
}

int main()
{
    signal(SIGCHLD,handler);
    if(fork() == 0)
    {
        sleep(5);
        std::cout << "子进程退出" << std::endl;
        exit(0);
    }
    while(true)
    {
        sleep(1);
    }
    return 0;
}

所以,现在我们对应的子进程退出时,确实会给父进程发送信号,我们就能基于信号,来进行回收子进程

#include <iostream>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> // 注意:原代码中使用了sleep函数,需包含此头文件
#include <wait.h>


void handler(int signo)
{
    std::cout << "get a sig: " << signo << std::endl;
    pid_t rid = ::waitpid(-1,nullptr,0);
    if(rid > 0)
    {
        std::cout << "子进程退出了,回收成功,child id: " << rid << std::endl;
    }
}

int main()
{
    signal(SIGCHLD,handler);
    if(fork() == 0)
    {
        sleep(5);
        std::cout << "子进程退出" << std::endl;
        exit(0);
    }
    while(true)
    {
        sleep(1);
    }
    return 0;
}

问题一:

如果是多个子进程一起退出呢?

#include <iostream>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> // 注意:原代码中使用了sleep函数,需包含此头文件
#include <wait.h>


void handler(int signo)
{
    std::cout << "get a sig: " << signo << std::endl;
    pid_t rid = ::waitpid(-1,nullptr,0);
    if(rid > 0)
    {
        std::cout << "子进程退出了,回收成功,child id: " << rid << std::endl;
    }
}

int main()
{
    signal(SIGCHLD,handler);
    for(int i = 0;i < 10; i++)
    {
        if(fork() == 0)
        {
            sleep(5);
            std::cout << "子进程退出" << std::endl;
            exit(0);
        }
    }
    
    while(true)
    {
        sleep(1);
    }
    return 0;
}

我们可以尝试循环wait,直到全部都回收

#include <iostream>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> // 注意:原代码中使用了sleep函数,需包含此头文件
#include <wait.h>


void handler(int signo)
{
    std::cout << "get a sig: " << signo << std::endl;
    while(true)
    {
        pid_t rid = ::waitpid(-1,nullptr,0);
        if(rid > 0)
        {
            std::cout << "子进程退出了,回收成功,child id: " << rid << std::endl;
        }
        else if(rid < 0)
        {
            std::cout << "暂时:回收完毕" << std::endl;
            break;
        } 
    }
}

int main()
{
    signal(SIGCHLD,handler);
    for(int i = 0;i < 10; i++)
    {
        if(fork() == 0)
        {
            sleep(5);
            std::cout << "子进程退出" << std::endl;
            exit(0);
        }
    }
    
    while(true)
    {
        sleep(1);
    }
    return 0;
}

问题二:

如果10个子进程,6个退出了,上面的代码会怎么办?

我们在等待第7个子进程的时候,会出现阻塞现象,我们要进行非阻塞等待

#include <iostream>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> // 注意:原代码中使用了sleep函数,需包含此头文件
#include <wait.h>


void handler(int signo)
{
    std::cout << "get a sig: " << signo << std::endl;
    while(true)
    {
        pid_t rid = ::waitpid(-1,nullptr,WNOHANG);
        if(rid > 0)
        {
            std::cout << "子进程退出了,回收成功,child id: " << rid << std::endl;
        }
        else if(rid == 0)
        {
            std::cout << "退出的子进程已经全部回收了" << std::endl;
            break;
        }
        else
        {
            std::cout << "wait error" << std::endl;
            break;
        } 
    }
}

int main()
{
    signal(SIGCHLD,handler);
    for(int i = 0;i < 10; i++)
    {
        if(fork() == 0)
        {
            sleep(5);
            std::cout << "子进程退出" << std::endl;
            exit(0);
        }
    }
    
    while(true)
    {
        sleep(1);
    }
    return 0;
}

还有一个简单操作,能直接对子进程进行回收

#include <iostream>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> // 注意:原代码中使用了sleep函数,需包含此头文件
#include <wait.h>


int main()
{
    //linux下 如果只想不产生僵尸,我们直接进行SIG_IGN就行了
    signal(SIGCHLD,SIG_IGN);
    for(int i = 0;i < 10; i++)
    {
        if(fork() == 0)
        {
            sleep(5);
            std::cout << "子进程退出" << std::endl;
            exit(0);
        }
    }
    
    while(true)
    {
        sleep(1);
    }
    return 0;
}

但是我们的SIG_IGN只是在linux下有用,我们手动设置的IGN和默认的IGN是不一样的

二.线程概念

三.Linux下线程的概念

一个执行流就是一个线程

四.进程 vs 线程

五.接口验证

#include <iostream>
#include <unistd.h>
#include <pthread.h>

//新线程
void* run(void* args)
{
    while(true)
    {
        std::cout << "new thread" << std::endl;
        sleep(1);
    }
    return nullptr;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,run,(void*)"thread-1");
    //主线程
    while(true)
    {
        std::cout << "main thread" << std::endl;
        sleep(1);
    }
    return 0;
}

如果是较新的版本,可能会自动带上我们对应的选项

"makefile"

mythread:mythread.cc
	g++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
	rm -rf mythread

这里确实是两个执行流

#include <iostream>
#include <unistd.h>
#include <pthread.h>

//新线程
void* run(void* args)
{
    while(true)
    {
        std::cout << "new thread, pid: " << getpid() << std::endl;
        sleep(1);
    }
    return nullptr;
}

int main()
{
    std::cout << "我是一个进程: " << getpid() << std::endl;
    pthread_t tid;
    pthread_create(&tid,nullptr,run,(void*)"thread-1");
    //主线程
    while(true)
    {
        std::cout << "main thread, pid: " << getpid() << std::endl;
        sleep(1);
    }
    return 0;
}



查看轻量级进程(ps -aL | grep mythread)

PID和LWP相同的就是我们对应的主线程,不相等的就是新线程

六.地址空间

1.分页式存储管理

2.多级页表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值