🔶线程
🔶makefile文件编写
🔱线程接口介绍
🔱创建线程——pthread_create
🔶补充pthread_self——获取本线程id
🔱线程退出——pthread_exit,pthread_cancel
🔱线程回收——pthread_join
🔱线程分离和joinable状态
🔱线程退出+回收的思维导图
🔱调用pthread库的执行过程
🔱pthread库
🔱局部存储——__thread编译选项
🔱错误总结
🔱线程切换比进程切换效率高
🍑线程
🍉makefile文件编写
g++ -pthread -o $@ $^ -std=c++11
g++ -o $@ $^ -std=c++11 -lpthread
两个都是对的,任选一个
因为pthread是一个动态库
,对于动态库我们需要告诉编一个库的名字,位置
如果不加就会找不到动态库
🍑线程接口介绍
🍐创建线程——pthread_create
功能:创建一个新的线程
参数:thread
:返回线程ID ,pthread_t类型
attr:设置线程的属性,attr为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg
:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码
传递的参数为void*类型
,表示可以传递任意类型的参数
🍐补充pthread_self——获取本线程id
我们以传递结构体为例
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<vector>
#include<functional>
#include<stdio.h>
#include<time.h>
using namespace std;
struct Thread
{
Thread(string name="thread_1",pthread_t id=0):_name(name),_id(id){}
string _name;
pthread_t _id;
};
void* fun(void* t)
{
((Thread*)t)->_id = pthread_self();
return nullptr;
}
int main()
{
pthread_t id;
Thread t("thread_1");
pthread_create(&id,nullptr,fun,&t);
sleep(1);
cout<<t._name<<" -> " << t._id<<endl;
return 0;
}
主线程想获取到子线程的id必须等一等
🍉线程退出——pthread_exit,pthread_cancel
线程退出不能使用exit退出
,exit是进程退出
- return,但是这种方式对主线程不适用,主线程使用return相当于exit
- pthread_exit
- pthread_cancel——
同一个进程
中A线程终止B线程
不可以自己终止自己使用pthread_cancel,不能子线程cancel父线程,后果自负
同时线程退出也是会有类似进程僵尸的情况发生的,需要对线程的退出进行管理
🍉线程回收——pthread_join
🍉线程分离和joinable状态
分离可以在主线程也可以在自己线程结束之前
线程默认为join able状态
分离态
就是子线程脱离父线程的管控
,不需要父线程回收资源
,可以使用cancel结束线程
🍉线程退出+回收的思维导图
🍐调用pthread库的执行过程
- 从磁盘加载代码到物理内存
- 将物理内存映射如地址空间
- 在运行到pthread库函数的时候跳到共享存储区中找相应的地址执行代码
- 执行完后跳回代码段继续执行
🍉pthread库
pthread封装了系统调用,在库中对内存和数据结构进行了管理
原本的虚拟地址空间——主线程使用
库中每个子线程都有一个空间
,id
对应的是虚拟地址
,并且每个空间都有自己的栈
,并且库中还有相应的库函数
所以在cancel的时候传入的是id——id存的是地址,直接通过地址去找需要结束的子线程,更改数据空间就可以了
🍐局部存储——__thread
编译选项
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<vector>
#include<functional>
#include<stdio.h>
#include<time.h>
using namespace std;
__thread int cnt = 100; // 表示每个线程都有一个变量存储在各自的栈中
void* fun(void* t)
{
while(1)
{
cnt--;
cout<<"thread_1 " << cnt<<endl;
sleep(1);
}
return nullptr;
}
int main()
{
pthread_t id;
pthread_create(&id,nullptr,fun,nullptr);
while(cnt)
{
cout<<"main thread " << cnt<<endl;
sleep(1);
}
return 0;
}
__thread
—— 每个线程
都有一个变量存储在各自的栈中
__thread只能对内置类型使用,不能对自定义类型使用(vector/string…)
🍑错误总结
- 多个线程各自有一个栈,共有一个堆
- 线程包含cpu现场,但是线程只是进程中的一个执行流,执行的是程序中的一个片段代码,多个线程完整整体程序的运行
- 线程的粒度小于进程,占用资源更少,因此通常多线程比多进程并发性更高
🍉线程切换比进程切换效率高
- 切换的寄存器少
线程
会将代码附近代码
加载进cpu的cache
中,在进行线程切换的时候有较大概率
使用cache中的代码
;但是在进程切换的时候,加载进cache中的代码就失效了,需要重新加载