目录
在Linux下创建线程依赖第三方库
因为在Linux中只有轻量级进程,因此整个第三方库只是一个对轻量级进程的封装
也因此,Linux自带一个叫做pthread的库
因此,创建线程的代码:
1、需要#include <pthread.h>
2、编译链接时,需加上库名:-lpthread
一、线程创建
每个线程有自己的栈、堆空间的理解:
一个在main函数栈中创建的变量,其他线程是可以看见的
因为地址资源共享,地址空间共享,这就会导致混淆、混乱
可能属于主线程的数据会被子线程修改,不具有独立性
因此,一般的线程的创建,各自线程的变量不要在栈空间中创建
而是在堆中创建,因为堆是需要地址才可以访问
再将该地址交给对应线程维护
如此,一个线程就相当于都有了一个对应的堆空间
线程创建函数:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);//这个函数是由第三方库pthread提供的
第一个参数:输出型参数,其实对无符号long长整型的封装,本质是虚拟地址
第二个参数:设为nullptr即可
第三个参数:一个函数指针,需要输入一个函数的地址,新线程会执行这部分代码
因为函数的返回值是void*,因此要获取void*的数据,就要使用void**的指针
而pthread_join等待函数的第二个参数就是void**,因此该参数就是为了获取执行函数的返回值
(void不能直接定义变量,但是void*可以,一个指针变量,有空间;可以理解为类似int的类型)
主线程可以通过这个参数,获取新线程的执行情况
当子线程崩溃时,进程也会崩溃
因此,子线程函数的返回值只考虑正确的情况,不考虑异常
同时,线程函数的返回值也是一个void*类型,因此可以设计任意对象的返回值
第四个参数:该参数传给第三个参数的函数形参,作为实参
第四个参数是void*类型,因此可以传递任意类型的对象,例如类对象
返回值:成功返回0;错误返回错误码
二、线程等待
int pthread_join(pthread_t thread, void **retval);//用于主线程等待线程的退出
第一个参数:要等待的线程 ID。
第二个参数:输出型参数,获取线程执行函数返回值
返回值:0等待成功
三、多线程的创建
1、线程id
2、执行方法
3、第四个参数可以传线程名
4、join
5、释放堆空间
注意:线程独立性
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <unistd.h>
#include <vector>
void* thread_run(void* arg)
{
sleep(1);
std::cout << (char*)arg << ": is runing ... " << std::endl;
return (void*)1111;
}
int main()
{
std::vector<pthread_t> tids;
for(int i = 0; i<10; i++)
{
tids.push_back(i);
char* name = new char[128];
pthread_create(&tids[i], nullptr, thread_run, (void*)name);
}
//等待
int64_t* return_val;
for(pthread_t tid : tids)
{
pthread_join(tid, (void**)return_val);
std::cout << "thread-" << tid << "quit" << std::endl;
}
return 0;
}
四、线程终止
1、线程函数return,线程结束
2、主线程退出,进程结束,所有线程结束;因此主线程最好最后退出
3、exit()函数是进程退出,不是线程退出,因此任意子线程调用exit()函数,会导致进程直接退出
4、void* pthread_exit(void *retval )函数:线程退出,参数获取线程执行函数返回值
5、int pthread_cancle(pthread_t thread )函数:取消线程,参数线程id;返回值-1
因此,线程的终止有三种情况:函数ureturn、退出、取消三种。
五、线程分离
线程执行完毕,自己退出,不用join等待
int pthread_detach(pthread_t thread);//线程分离
pthread_t pthread_self(void);//获取当前线程id
如果线程已经分离,却依旧等待,就会出错,等待函数返回值为22
但是即使线程分离,如果子线程崩溃,依旧会导致进程崩溃
因为虽然是分离,但是实际上还是处于一个进程内部,共享同一个地址空间
可以子线程自己分离自己,也可以由主线程分离其他子线程
C++多线程:
C++11的多线程就是对Linux的原生库函数的封装
事实上,Linux环境下的所有语言,例如C、java、python等都是对原生库函数的封装,这是语言跨平台的本质,注意,是快平台,而不是跨环境。