linux之线程控制(万字长文详解)

时间:2024-01-23 15:29:20

线程是可以的等待!使用join进行阻塞式的等待,如果不等待会造成类似僵尸进程之类的内存泄漏的问题!——==但是如果我们无论如何都不想等待呢?==

进程我们可以通过捕抓特定的信号来不对子进程进行等待,从而也能做到子进程结束的时候,也能回收子进程——但是线程不可以,因为信号是作用于进程的!

要做到这一点我们可以进行线程分离!——什么是线程分离,默认情况下,新创建的线程所对应被等待状态是joinable,表示这个线程是必须被join的!线程退出后,需要对其进行pthread_join操作,否则无法释放 资源,从而造成系统泄漏

如果不关心线程的返回值,join此时是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。——==这种策略就是线程分离!==

==线程分离有两种——一种主线程分离新线程!一种是新线程自己分离==

线程分离是要通过线程的id来进行分离的!——那么新线程是如何知道自己的id的呢?

image-20230814103554591

==pthread_self==这个函数的作用就是获取调用这个函数的线程的id!该函数默认一直都是成功的!所以返回值都是该线程的id!

#include<iostream>
#include<pthread.h>
#include<cstdio>
#include<string>
#include<unistd.h>
using namespace std;
string changeId(const pthread_t& thread_id)
{
    char tid[128];
    snprintf(tid, sizeof tid, "0x%x",thread_id);
    return tid;
}
void* start_routine(void* args)
{
    string threadname = static_cast<const char*>(args);
    while(true)
    {
        changeId(pthread_self());
        cout << threadname << " running.... " <<changeId(pthread_self())<<endl;
        sleep(1);
    }
}
int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
    string main_id = changeId(pthread_self());
    cout << "main running.... new thread id:" <<changeId(tid) << " main id : "<<main_id <<endl;

    pthread_join(tid,nullptr);
    return 0;
}

image-20230814104742872

==我们可以看到pthread_self获取到的id和我们的主线程里面新线程的id是一致的!==

线程分离的函数是pthread_detach

image-20230814105113448

该函数的作用就是分离一个线程!

==返回值——成功返回0,错误返回一个错误码!==

==一个线程默认状态是joinable的!如果设置了分离就不能等待了==

#include<iostream>
#include<pthread.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<unistd.h>
using namespace std;
string changeId(const pthread_t& thread_id)
{
    char tid[128];
    snprintf(tid, sizeof tid, "0x%x",thread_id);
    return tid;
}
void* start_routine(void* args)
{
    string threadname = static_cast<const char*>(args);
    sleep(3);//如果我们这里加一个sleep会发生什么呢?
    pthread_detach(pthread_self());//设置自己为分离状态!
    int cnt = 5;

    while(cnt--)
    {
        cout << threadname << " running.... " <<changeId(pthread_self())<<endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
    string main_id = changeId(pthread_self());
    cout << "main running.... new thread id:" <<changeId(tid) << " main id : "<<main_id <<endl;
    
    //一个线程默认状态是joinable的!如果设置了分离就不能等待了!
    int n = pthread_join(tid,nullptr);
    cout << "result: " << n << " : " << strerror(n) <<endl;
    return 0;
}

image-20230814112152211

我们发现——等待成功了!不是说分离了就不能等待吗?为什么会发生这样的情况?

image-20230814113515352

==这就就是分离慢,等待快==

int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
    string main_id = changeId(pthread_self());
    cout << "main running.... new thread id:" <<changeId(tid) << " main id : "<<main_id <<endl;
    
    sleep(5);//如果是在这里sleep
    int n = pthread_join(tid,nullptr);
    cout << "result: " << n << " : " << strerror(n) <<endl;
    return 0;
}

image-20230814113656164

==等待慢,分离快!——那么就可以得到正常的结果!==

如果都不sleep就看操作系统的调度!那种情况都可能发生!

==所以我们毕竟推荐的是不要让新线程自己去分离!,而是让主线程自己去直接分离新线程!==

#include<iostream>
#include<pthread.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<unistd.h>
using namespace std;
string changeId(const pthread_t& thread_id)
{
    char tid[128];
    snprintf(tid, sizeof tid, "0x%x",thread_id);
    return tid;
}
void* start_routine(void* args)
{
    string threadname = static_cast<const char*>(args);
    sleep(3);
    pthread_detach(pthread_self());//设置自己为分离状态!
    int cnt = 5;

    while(cnt--)
    {
        cout << threadname << " running.... " <<changeId(pthread_self())<<endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
    pthread_detach(tid);//主线程自己手动分离!

    string main_id = changeId(pthread_self());
    cout << "main running.... new thread id:" <<changeId(tid) << " main id : "<<main_id <<endl;

    int n = pthread_join(tid,nullptr);
    cout << "result: " << n << " : " << strerror(n) <<endl;
    return 0;
}

==这样子我们就可以保证!一定是先分离!再join,那么我们就用在做后面的join的工作了!==

==这样子就可以让主线程去安心做自己的工作了!==

#include<iostream>
#include<pthread.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<unistd.h>
using namespace std;
string changeId(const pthread_t& thread_id)
{
    char tid[128];
    snprintf(tid, sizeof tid, "0x%x",thread_id);
    return tid;
}
void* start_routine(void* args)
{
    string threadname = static_cast<const char*>(args);
    pthread_detach(pthread_self());//设置自己为分离状态!
    int cnt = 5;

    while(cnt--)
    {
        cout << threadname << " running.... " <<changeId(pthread_self())<<endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
    pthread_detach(tid);//主线程自己手动分离!

    string main_id = changeId(pthread_self());

    while(true)
    {
        cout << "main running.... new thread id:" << changeId(tid) << " main id : " << main_id << endl;
        sleep(1);
    }
    return 0;
}

image-20230814114635738

==新线程跑完了就会自动的被回收!==