0
点赞
收藏
分享

微信扫一扫

2023年7月京东笔记本电脑行业品牌销售排行榜(京东数据平台)

伽马星系 2023-09-07 阅读 46
linux

目录

一、线程创建

1.1 pthread_create

1.2 线程传入启动函数参数方式

二、线程退出(pthread_exit函数 pthread_cancel函数)

三、线程等待

3.1 为什么要线程等待?

3.2 pthread_join函数

 四、线程分离

4.1 pthread_detach() 和 pthread_self()

五、pthread库维护线程的基本结构


一、线程创建

1.1 pthread_create

1.2 线程传入启动函数参数方式

关于第四个参数,我们要注意其是void*类型指针,任意指针都可以传给线程!现在我们模拟一种错误的传参方式,传栈区资源,基于线程运行顺序产生的传参问题!

#define NUM 5
void* pthread_route(void* args)
{
    const char* name = (const char*)args;
    cout << "new thread create success, its name: "<<name<<endl;
}

int main()
{
    pthread_t pid;
    for(int i=0;i<NUM;i++)
    {
        char buffer[64];
        snprintf(buffer,sizeof(buffer),"thread %d",i+1);
        pthread_create(&pid,nullptr,pthread_route,buffer);
    }
    sleep(1);
    return 0;
}

运行结果: 


正确的传参方式:数据放入堆区,传堆区指针!

#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
#define NUM 3
using namespace std;

//每个线程独立的资源 线程ID + 线程buffer
class Thread_data
{
public:
    pthread_t _pid;
    char namebuffer[64];
};

void *thread_route(void *args)
{
    Thread_data *p = static_cast<Thread_data *>(args);
    int cnt = 3;
    while (cnt--)
    {
        cout << "new thread create success,its name: " << p->namebuffer << " &cnt: " << &cnt <<" cnt= "<<cnt<<endl;
    }
    delete p;
    return nullptr;
}

int main()
{
    for (int i = 0; i < NUM; i++)
    {
        Thread_data *pt = new Thread_data();
        snprintf(pt->namebuffer, sizeof(pt->namebuffer), "thread %d", i + 1);
        pthread_create(&pt->_pid, nullptr, thread_route, pt);
    }
    sleep(1);
    return 0;
}

运行结果: 


二、线程退出(pthread_exit函数 pthread_cancel函数)


三、线程等待

3.1 为什么要线程等待?

为什么要有线程等待?回想以前的进程等待,父进程回收子进程,获取子进程退出信息!

对于已经退出的线程,其空间没有被释放,仍在进程的地址空间内!所以创造新的线程不会复用刚才退出线程的地址空间,这就造成了资源的浪费!

3.2 pthread_join函数

线程的调用逻辑函数返回值是void*,该函数会在线程结束前将线程结束状态码保存进pthread库中,打个比方它的数字状态码是10,然后通过强转(void*)10,将4字节整形放入8字节的指针中(Linux下指针默认是64位下!)。外部获取函数内部结果,我们需要传地址,所以要传void**!

需要知道的是,我们返回的值一定是右值!也就输说常变量、堆空间资源可以返回!栈上数据不能返回因为函数栈帧结束后栈空间数据会被销毁!

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

using namespace std;
#define NUM 5
class pthread_data
{
public:
    pthread_t tid;
    char buffer[128];
};
class Thread_ret
{
public:
    int exit_code;
    int exit_result;
};

void* pthread_route(void* args)
{
    Thread_ret* ret = new Thread_ret();
    int cnt = 5;
    while(cnt)
    {
        cout <<"cnt: " << cnt-- <<" &cnt:" <<&cnt<<endl;//BUG?
        sleep(1);
    }
    ret->exit_code = 106;
    ret->exit_result = 0;
    return (void*)ret;
}
int main()
{
    vector<pthread_data*> vp;

    for(int i=0;i<NUM;i++)
    {
        pthread_data* pd = new pthread_data();
        pthread_create(&pd->tid,nullptr,pthread_route,pd);
        snprintf(pd->buffer,sizeof(pd->buffer),"thread :%d pid:0x%x ",i+1,pd->tid);
        vp.push_back(pd);
    }

    for(auto& e : vp)
    {
        cout << "creat thread success: " << e->buffer<<endl;
    }

    for(auto&e :vp)
    {
        Thread_ret* ret;
        pthread_join(e->tid,(void**)(&ret));
        cout <<"join :" <<e->buffer<<" success " <<"exit code:" <<ret->exit_code <<" exit result: " <<ret->exit_result<<endl;
        delete e;
    }

    cout <<"main quit!"<<endl;
    return 0;
}


 四、线程分离

1.默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
2.如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。

4.1 pthread_detach() 和 pthread_self()

分离线程,可以是指定的其他线程,也可以是自己!

int pthread_detach(pthread_t thread);

pthread_self()获取线程自己的ID!


五、pthread库维护线程的基本结构

在前面我们了解到线程有属于自己的ID、私有栈等等结构,这些线程肯定需要被组织!如何组织呢?在Linux下线程库内用结构体(TCP)对每个线程进行组织!库其实本质是磁盘上的文件,在链接的时候将内容加载到内存的共享区内,也就是说我们的线程的属性存储在共享区内!线程的私有栈区实在共享区内!

 线程的局部存储:可以使一个全局变量让所有线程私有栈内创建一份!

在全局变量前面加上__thread 即可 !


举报

相关推荐

0 条评论