C++ 11 之后出现了线程pthread ,今天我们来认识一下:
1、创建线程 pthread_create
说明:
**参数说明:** **第一个参数:线程ID** **第二个参数:线程属性,用0即可** **第三个参数:函数指针(耗时操作函数名)** **第四个参数:函数指针的参数**
引入库:#include <pthread.h>
1、c++中的线程和main函数默认是互不相关的,也就是说main函数弹栈后不管子线程是否完成,就会结束子线程(允许异常)
2、可以使用join来让子线程完成后再执行join后面的代码,直至main函数弹栈
3、千万不要让main函数睡眠的方式等待异步线程
示例代码:
// 异步线程 相当于Java的Thread.run函数一样
void *customPthreadTask(void *pVoid) {
// C++转换static_cast 转换指针操作的
int *number = static_cast<int *>(pVoid); // pVoid==number int的地址,所以我用int*接收,很合理
cout << "异步线程执行了:" << *number << endl;
for (int i = 0; i < 10; ++i) {
cout << "run:" << i << endl;
sleep(1);
}
return 0; // 必须返回
}
int main(){
int number = 9527;
pthread_t pthreadID; // 线程ID,每个线程都需要有的线程ID
pthread_create(&pthreadID, 0, customPthreadTask, &number);
pthread_join(pthreadID,0); //此处不join,会随着main函数弹栈,而结束子线程
return 0;
}
/**
异步线程执行了:9527
run:0
run:1
run:2
run:3
run:4
run:5
run:6
run:7
run:8
run:9
*/
2、分离线程和非分离线程
说明:
**1、分离线程:各个线程都是自己运行自己的,互不相关。例如:main函数结束,就全部结束,不会等待异步线程。** **多线程情况下使用** **2、非分离线程:线程之间有协作的能力,例如:main函数会等待异步线程执行完后,再执行后面的代码** **协作、顺序指向的场景**
3、互斥锁(相当于java的synchronize)
说明:
**1、不允许有野指针,所有必须要初始化** **2、pthread_mutex_init 初始化 、pthread_mutex_destroy销毁锁,必须成对出现,两者之间的代码是加了锁的;**
示例代码:
queue<int> data;//全局的存储队列
pthread_mutex_t mutex;//定义一个互斥锁,不允许有野指针
void *task(void *pVoid) {
pthread_mutex_lock(&mutex); // 锁住
cout << "当前线程的标记是:" << *static_cast<int *>(pVoid) << endl;
if (!data.empty()) {
printf("获取队列的数据:%d\n", data.front());
data.pop(); // 删除
} else {
printf("没有数据了\n");
}
sleep(1);
pthread_mutex_unlock(&mutex); // 解锁
return 0;
}
int main(){
//初始化
pthread_mutex_init(&mutex, NULL);
// 给队列 初始化数据 手动增加数据进去
for (int i = 10001; i < 10111; ++i) {
data.push(i);
}
//定义10个线程
pthread_t pthreadIDArray[20];
for (int i = 0; i < 20; ++i) {
pthread_create(&pthreadIDArray[i], 0, task, &i);
// 不能使用 join,如果使用(就变成顺序的方式,就没有多线程的意义了,所以不能写join)
// pthread_join(pthreadIDArray[i], 0);
}
sleep(20);
// 销毁 互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}
4、条件变量+互斥锁 == Java版本的(notify 与 wait 操作)
说明:
**pthread_cond_broadcast====Java notifyAll 所有的** **pthread_cond_signal===== Java notify 单个的**
1、互斥锁(pthread_mutex_t)、条件变量(pthread_cond_t)都不允许有野指针
2、结合使用时, 初始化:先初始化互斥锁,再初始化条件变量;
**释放:先回收互斥锁,再回收条件变量;**
1)定义一个模板队列:
#include <iostream>
#include <string>
#include <pthread.h>
#include <string>
#include <queue>
using namespace std;
template<typename T>
class SafeQueue{
private:
queue<T> queue;
pthread_mutex_t mutex; // 定义互斥锁(不允许有野指针)
pthread_cond_t cond; // 条件变量,为了实现 等待 读取 等功能 (不允许有野指针)
public:
SafeQueue(){
// 初始化 互斥锁
pthread_mutex_init(&mutex, 0);
// 初始化 条件变量
pthread_cond_init(&cond, 0);
}
~SafeQueue() {
// 回收 互斥锁
pthread_mutex_destroy(&mutex);
// 回收 条件变量
pthread_cond_destroy(&cond);
}
public:
void add(T t){
// 为了安全 加锁
pthread_mutex_lock(&mutex);
queue.push(t); // 把数据加入到队列中
// 告诉消费者,我已经生产好了
// pthread_cond_signal(&cond) // Java notify 单个的
pthread_cond_broadcast(&cond); // Java notifyAll 所有的的
// 解锁
pthread_mutex_unlock(&mutex);
}
void get(T & t){
// 为了安全 加锁
pthread_mutex_lock(&mutex);
while (queue.empty()) {
cout << "等待中.." << endl;
pthread_cond_wait(&cond, &mutex); // 相当于 Java的 wait 等待了[有可能被系统唤醒]
}
// 证明被唤醒了
t = queue.front(); // 得到 队列中的元素数据 仅此而已
queue.pop(); // 删除元素
// 解锁
pthread_mutex_unlock(&mutex);
}
};
2)模拟生产者、消费者
#include "SafeQueue.h"
SafeQueue<int> sq;
// TODO 模拟演示 消费者
void *getMethod(void *) {
while (true) {
int value;
sq.get(value);
printf("消费者get 得到的数据:%d\n", value);
// 你只要传入 -1 就结束当前循环
if (-1 == value) {
break;
}
}
return 0;
}
// TODO 模拟演示 生产者
void *setMethod(void *) {
while (true) {
int value;
printf("请输入你要生成的信息:\n");
cin >> value;
sq.add(value);
if (value == -1) {
break;
}
}
return 0;
}
int main(){
pthread_t pthreadGet;
pthread_create(&pthreadGet, 0, getMethod, 0);//1
pthread_t pthreadSet;
pthread_create(&pthreadSet, 0, setMethod, 0);//2
pthread_join(pthreadGet, 0);//不能在线程创建成功就join ,否则达不到两个线程同时执行的效果
pthread_join(pthreadSet, 0);
return 0;
}
这一节的内容其实和java的对比着学习,会比较容易理解些。
特别需要注意的是:
<u>加锁与销毁锁是成对出现的,千万不要忘记销毁锁;</u>
网友评论