【Linux】线程控制

接口

pthread_create()线程创建

  • pthread_t* thread:输出型参数,将线程的tid值放入到我们外部创建好的pthread_t 类型的变量中。
  • const pthread_attr_t *attr:用来设置线程属性,一般情况下设置成nullptr,等用到的时候再详细讲解。
  • void* (*start_routine)(void *):函数指针,这是一个回调函数,该函数的内容就是新线程要执行的
  • void* arg:回到函数的参数。
  • 返回值: 线程创建成功返回0,不成功返回错误码。
cpp 复制代码
#include<iostream>
#include<unistd.h>
#include<pthread.h>

using namespace std;

#define NUM 10

void* test(void* args)
{
    sleep(1);
    string name = (char*) (args);
    while(1)
    {
        cout << "new thread name:" << name << endl;
        sleep(1);
    }
}
int main()
{
    
    for (int i = 0; i < NUM; i ++)
    {
        pthread_t tid;
        char buffer[64];
        snprintf(buffer, sizeof buffer, "thread %d", i+1);
        pthread_create(&tid, nullptr, test, (void*)buffer);
    }

    while(1)
    {
        cout << "create success..." << endl; 
        sleep(1);
    }

    return 0;
}

运行结果如下:

为什么会导致这样的结果?

观察上面主线程创建子线程的时候,我们在for循环里定义了buffer缓冲区,然后将线程的名字打印进buffer中。

理想的结果是打印thread 1, thread 2, thread3...但是结果是只打印了thread10。

原因:

1、buffer的生命周期在for循环内部,当跳出循环的时候buffer就消失了,新创建的buffer会继续在上一个buffer的地址位置创建新的buffer。

2、因为buffer生命周期的原因,并且pthread_create传递的是buffer的地址,所以,其实所有的线程拿到的是同一个缓冲区。pthead 1,phtead2等等会被后面的线程覆盖,最后都变成pthread10。

所以,为了让所有的线程都有自己的缓冲区,可以new一个空间给每个空间。避免了生命周期的问题。

1、解决方法一

2、解决方法二

使用类,将内容写入到每个线程的类中。

执行结果:

pthread_exit()结束线程

  • 参数:返回线程结束信息,当前阶段设置成nullptr即可。

执行结果:

pthread_join()线程等待函数

和进程等待一样,将线程回收,避免内存泄漏

  • pthread_t thread:要等待的线程tid。
  • void** retval:线程结束信息返回,这是一个输出型参数。
  • 返回值:等待成功返回0,等待失败返回错误码。

运行结果:

线程等待返回值

运行结果:

所以,可以通过线程等待的返回值判断线程是不是正常退出

pthread_canel()取消线程

pthread_self()查看线程tid

查看线程自己的tid,和查看进程的pid一样,接口是pthread_join

作用就是查看调用该函数的线程的tid

pthead_detach()线程分离

从上面的各种结果可以看出,线程等待是阻塞等待

按道理说,应该是主线程边打印,子线程边进行。但是程序执行的结果表示,子线程执行完了再执行主线程的内容。

当主线程不关注子线程的退出情况的时候,阻塞等待就现得很没用。所以,我们可不可以不进行阻塞等待呢?

可以。

返回值:成功返回0,失败返回错误码

一个线程不能既是joinable,又是分离的**。将线程设置为分离的之后,主线程将不再关心线程的退出状态,子线程会自动释放**。

线程分离之后再进行线程等待会失败

cpp 复制代码
void* test(void* args)
{
    sleep(1);
    char *name = (char*)args;
    //进行线程分离
    pthread_detach(pthread_self());
    int cnt = 5;
    while(cnt--)
    {
        cout << "new thread name:" << name << endl;
        sleep(1);
    }

    return (void*) 1;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, test, (void *)"thread one");
    int n = pthread_join(tid, nullptr);
    cout << "join pthread -> " << strerror(n) << endl;
    return 0;
}

执行结果:

线程等待成功

不是说线程分离了再进行线程等待就会失败吗?怎么上面的运行结果仍然是等待成功呢

因为主线程先被调度,在新线程被创建但是没有执行的时候主线程就开始等待新线程了。

所以当新线程将自己分离以后,主线程已经处于等待状态了,它不认为新线程被分离,还会继续等待,而且可以等待成功。

如果让主线程先等待一会儿,让新线程先执行,就可以看到线程等待失败

执行结果:

正确的做法:在主线程中分离新线程

cpp 复制代码
void* test(void* args)
{
    sleep(1);
    char *name = (char*)args;
    int cnt = 5;
    while(cnt--)
    {
        cout << "new thread name:" << name << endl;
        sleep(1);
    }

    return (void*) 1;
}
int main()
{
    pthread_t tid;
    cout << "主线程tid: " << pthread_self() << endl;
    
    pthread_create(&tid, nullptr, test, (void *)"thread one");
    pthread_detach(tid);
    int n = pthread_join(tid, nullptr);
    cout << "join pthread -> " << strerror(n) << endl;

    while(1)
    {
        cout << "主线程..." << endl;
        sleep(1);
    }

    return 0;
}

这样做的好处是,在主线程等待失败之后,主线程并不会阻塞。从后来一直打印"主线程..."这里可以看出来。

相关推荐
老歌老听老掉牙4 分钟前
QT开发踩坑记:按钮点击一次却触发两次?深入解析信号槽自动连接机制
c++·qt
Dxy12393102167 分钟前
中文乱码恢复方案
开发语言·python
香蕉你个不拿拿^14 分钟前
Linux进程地址空间解析
linux·运维·服务器
橘色的喵15 分钟前
现代 C++17 相比 C 的不可替代优势
c语言·c++·现代c++·c++17
人间打气筒(Ada)21 分钟前
Linux学习~日志文件参考
linux·运维·服务器·学习·日志·log·问题修复
浅念-25 分钟前
C/C++内存管理
c语言·开发语言·c++·经验分享·笔记·学习
回敲代码的猴子34 分钟前
2月8日上机
开发语言·c++·算法
rongyili881 小时前
Dify 外部知识库集成 Milvus 实战指南
开发语言·python·milvus
xuhe21 小时前
Claude Code配合Astro + GitHub Pages:为 sharelatex-ce 打造现代化的开源项目宣传页
linux·git·docker·github·浏览器·overleaf
charlie1145141911 小时前
RK3568跑Arch Linux全路程指南(以正点原子的RK3568开发板为例子)
linux·嵌入式·rootfs·教程·环境配置·嵌入式linux·工程实践