【Linux】多线程(2)

简介: 【Linux】多线程

6、线程分离

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

线程分离的函数:

int pthread_detach(pthread_t thread);

可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离joinable和分离是冲突的,一个线程不能既是joinable又是分离的。

下面我们进行线程分离以后再进行等待,看看会发生什么。

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
void* threadRoutine(void* args)
{
    int cnt = 3;
    while (cnt--)
    {
        std::cout << "new thread run..." << std::endl;
    }
    return nullptr;
}
int main()
{
    pthread_t t1;
    pthread_create(&t1, nullptr, threadRoutine, nullptr);
  // 线程分离
    pthread_detach(t1);
  //  线程等待
    int error = pthread_join(t1, nullptr);
    if (error == 0)
    {
        std::cout << "等待成功" << std::endl;
    }
    else
    {
        std::cout << "等待失败,错误码" << error << ",错误原因:" << strerror(error) << std::endl;
    }
    return 0;
}

由于我们对新线程进行了线程分离,所以主线程等待错误,将错误信息进行打印,主线程退出,新线程也要跟着退出。

三、Linux线程数据

1、共享与私有的对比

我们知道线程共享进程数据,但也拥有自己的一部分私有数据

  • 线程ID。
  • 一组寄存器。(存储每个线程的上下文信息)
  • 。(每个线程都有临时的数据,需要压栈出栈)
  • errno。(C语言提供的全局变量,每个线程都有自己的)
  • 信号屏蔽字。
  • 调度优先级。

进程的多个线程共享 同一地址空间,因此代码段、数据段都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

  • 文件描述符表。(进程打开一个文件后,其他线程也能够看到)
  • 每种信号的处理方式。(SIG_IGN、SIG_DFL或者自定义的信号处理函数)
  • 当前工作目录。(pwd)
  • 用户ID和组ID。

2、Linux线程库的深入理解

我们知道Linux线程库是一个动态库,当我们多线程程序在运行时动态库需要被加载到共享区内的。

创建出来的线程是要被进行管理的,由于Linux不提供真正的线程,只提供LWP,也就意味着操作系统只需要对内核执行流LWP进行管理,而供用户使用的线程接口等其他数据,应该由线程库自己来管理,因此管理线程的工作就应该在线程库里进行。

于是线程库里面为我们提供了一个个类似于tid的结构,这个结构里面包含了struct_pthread(存储了线程的许多属性),线程局部存储线程栈(这就是为什么每个线程都有独立的栈结构,主线程用的是进程系统栈,新线程用的是库中提供的栈),我们以前常用的pthread_t类型存储的值就是这个类似于tid结构的首地址

下面一个代码将pthread_t转换为16进制的地址:

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <string>
#include <pthread.h>
// 16进制转换
std::string HexAdress(pthread_t tid)
{
    char str[64];
    snprintf(str, sizeof(str), "0x%x", tid);
    std::string s (str);
    return s;
}
void* threadRoutine(void* args)
{
    int cnt = 3;
    while (cnt--)
    {
        std::cout << "new thread aderss : " << HexAdress(pthread_self()) << std::endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    pthread_t t1;
    pthread_create(&t1, nullptr, threadRoutine, nullptr);
  // 线程分离
    pthread_detach(t1);
    sleep(5);
    return 0;
}


实际上我们线程创建对应的pthread_creat使用的就是clone系统调用,从前到后参数的意义以此是:要执行的函数,独立栈的地址,创建的一些选项,传给参数1的函数参数。


__threadGCC内置的线程局部存储设施,__thread修饰的全局变量(内置类型)每一个线程有一份独立实体,各个线程的值互不干扰,因为它们都被存储到了线程库管理结构中的线程局部存储内。

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <pthread.h>
// __thread修饰全局变量
__thread int g_val = 10;
void* threadRoutine(void* args)
{
    long long a = (long long)args;
    int cnt = 3;
    while (cnt--)
    {
        std::cout << "线程" << a << ",g_val : " << (g_val++ * a) << std::endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    pthread_t t1, t2, t3;
    pthread_create(&t1, nullptr, threadRoutine, (void*)1);
    usleep(1000);
    pthread_create(&t2, nullptr, threadRoutine, (void*)2);
    usleep(1000);
    pthread_create(&t3, nullptr, threadRoutine, (void*)3);
  // 线程分离
    pthread_detach(t1);
    pthread_detach(t2);
    pthread_detach(t3);
    sleep(5);
    return 0;
}

相关文章
|
1月前
|
Linux C++
LInux下Posix的传统线程示例
LInux下Posix的传统线程示例
20 1
|
1月前
|
Linux
Linux 查看进程PID和线程CPU和内存占用情况
Linux 查看进程PID和线程CPU和内存占用情况
22 0
|
2月前
|
算法 Unix Linux
Linux与Qt线程优先级的对应关系:一次全面解析
Linux与Qt线程优先级的对应关系:一次全面解析
24 0
|
2月前
|
消息中间件 Linux 调度
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
74 0
|
2月前
|
资源调度 算法 Linux
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
123 0
|
2月前
|
存储 安全 数据管理
Linux系统编程教程之Linux线程函数的使用:讲解Linux线程函数
Linux系统编程教程之Linux线程函数的使用:讲解Linux线程函数
19 1
|
8天前
|
存储 缓存 Java
【linux线程(四)】初识线程池&手撕线程池
【linux线程(四)】初识线程池&手撕线程池
|
8天前
|
Java Linux
【linux线程(三)】生产者消费者模型详解(多版本)
【linux线程(三)】生产者消费者模型详解(多版本)
|
8天前
|
安全 Linux 调度
【linux线程(二)】线程互斥与线程同步
【linux线程(二)】线程互斥与线程同步
|
8天前
|
Linux 调度
【linux线程(一)】什么是线程?怎样操作线程?
【linux线程(一)】什么是线程?怎样操作线程?