*🍑个人主页:Jupiter.🚀 所属专栏:Linux从入门到进阶欢迎大家点赞收藏评论😊*
目录
🚲Linux线程控制
🐏POSIX线程库
在Linux中,
没有线程的概念,只有轻量级进程的概念
,所以Linux系统只提供了轻量级进程的系统调用,没有线程相关的系统调用,但是用户不知道轻量级进程的概念,只知道线程和进程,所以
Linux将轻量级进程的系统调用进行封装
,转成线程相关的接口语义提供给用户,就
形成了pthread库
。
- 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以
“pthread_”
开头的。 - 要使用这些函数库,要通过引入头文
<pthread.h>
。 - 链接这些线程函数库时要使用
编译器命令
的“-lpthread”
选项。
🐕创建线程
- 功能:创建一个新的线程
- 原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
- 参数- thread:返回线程ID- attr:设置线程的属性,attr为NULL表示使用默认属性- start_routine:是个函数地址,线程启动后要执行的函数- arg:传给线程启动函数的参数(
可以是对象
等等)- 返回值:成功返回0;失败返回错误码 - 错误检查:- 传统的一些函数是,
成功返回0,失败返回-1
,并且对全局变量errno赋值以指示错误。-pthreads函数
出错时不会设置全局变量errno
(而大部分其他POSIX函数会这样做)。而是将错误代码通过返回值返回
pthreads同样也提供了线程内的errno变量,以支持其它使用errno的代码。对于pthreads函数的错误,建议通过返回值判定,因为读取返回值要比读取线程内的errno变量的开销更小。
注意:
新线程和主线程谁先运行?这是未知的。
示例代码:
#include<iostream>#include<unistd.h>#include<pthread.h>void*routine(void*name){
std::cout <<"i am new thread,name:"<<(char*)name << std::endl;sleep(1);returnnullptr;}intmain(){
pthread_t tid;pthread_create(&tid,nullptr, routine,(void*)("thread-1"));while(true){
std::cout <<"i am process,pid:"<<getpid()<< std::endl;sleep(1);}return0;}
运行结果:
🐟指令查看轻量级进程
指令:ps -aL
根据上面的结果可知:他们的pid一样,所以属于同一个进程,而且可知:
OS在进行调度的时候,用的是LWP进行调度的
。(因为pid可能一样,不能唯一性标识)
🐒线程ID及进程地址空间布局
pthread_ create函数会产生一个线程ID
,存放在第一个参数指向的地址中。- 前面讲的线程ID属于进程调度的范畴。因为线程是
轻量级进程
,是操作系统调度器的最小单位
,所以需要一个数值来唯一表示该线程。 pthread_ create函数
第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。
线程库NPTL提供了
pthread_ self函数
,可以获得
线程自身的ID
:
pthread_t pthread_self(void);
pthread_t 到底是什么类型呢?
- 取决于实现。对于Linux目前实现的NPTL实现而言,
pthread_t类型的线程ID
,本质就是一个进程地址空间上的一个地址
。 线程的管理
由库维护
,即描述线程的结构体与管理线程的数据结构(类似于数组)就在库里面的,其中pthread_t tid
即是描述tid线程结构体的起始地址
。线程的栈与局部存储
是在库中维护的。虽然栈是线程独立的,但是其他线程也是可以访问的。
示例代码:
#include<iostream>#include<unistd.h>#include<pthread.h>#include<string.h>#include<stdio.h>
std::string ToHex(pthread_t tid)//将id转换为十六进制{char buff[64];snprintf(buff,64,"0x%lx", tid);return buff;}void*routine(void*name){while(true){sleep(1);
std::cout <<"i am new thread,name:"<<(char*)name <<" my tid is :"<<ToHex(pthread_self())<< std::endl;}returnnullptr;}intmain(){
pthread_t tid;pthread_create(&tid,nullptr, routine,(void*)("thread-1"));while(true){
std::cout <<"i am process,pid:"<<getpid()<<" new thread id:"<<ToHex(tid)<< std::endl;sleep(1);}return0;}
运行结果:
🦔__thread与线程的局部存储
__thread
是 C 和 C++ 中用于声明线程局部存储
的一个关键字(或属性,具体取决于编译器和平台)。它告诉编译器或链接器
,被__thread 修饰的变量
是每个线程私有
的,即每个线程都有该变量的一个独立实例
,这些实例之间互不影响。如:__thread int tls_variable = 0; 一般对于全局变量使用。 示例代码:
#include<pthread.h>#include<stdio.h>// 声明一个线程局部变量
__thread int tls_variable =0;void*thread_function(void* arg){
tls_variable =(int)arg;// 每个线程都会修改它自己的 tls_variable 副本 printf("Thread %ld has tls_variable = %d\n",(long)pthread_self(), tls_variable);returnNULL;}intmain(){
pthread_t threads[2];// 创建两个线程,每个线程将接收到一个不同的参数 pthread_create(&threads[0],NULL, thread_function,(void*)1);pthread_create(&threads[1],NULL, thread_function,(void*)2);// 等待两个线程完成 pthread_join(threads[0],NULL);pthread_join(threads[1],NULL);return0;}
版权归原作者 Jupiter· 所有, 如有侵权,请联系我们删除。