【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;
}

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

相关推荐
Charles Ray3 分钟前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
重生之我在20年代敲代码4 分钟前
strncpy函数的使用和模拟实现
c语言·开发语言·c++·经验分享·笔记
爱上语文5 分钟前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
小安运维日记1 小时前
Linux云计算 |【第四阶段】NOSQL-DAY1
linux·运维·redis·sql·云计算·nosql
编程零零七2 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
2401_858286113 小时前
52.【C语言】 字符函数和字符串函数(strcat函数)
c语言·开发语言
铁松溜达py3 小时前
编译器/工具链环境:GCC vs LLVM/Clang,MSVCRT vs UCRT
开发语言·网络
everyStudy3 小时前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
CoolTiger、4 小时前
【Vmware16安装教程】
linux·虚拟机·vmware16
C-SDN花园GGbond5 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法