简单总结下C++自带的 std::thread
优点:
1. 简单,易用
2. 跨平台,pthread只能用在POSIX系统上(其他系统有其独立的thread实现)
3. 提供了更多高级功能,比如future
4. 更加C++(跟匿名函数,std::bind,RAII等C++特性更好的集成)
缺点:
1. 没有RWlock。有一个类似的shared_mutex,不过它属于C++14,你的编译器很有可能不支持。
2. 操作线程和Mutex等的API较少。毕竟为了跨平台,只能选取各原生实现的子集。如果你需要设置某些属性,需要通过API调用返回原生平台上的对应对象,再对返回的对象进行操作。
joinable函数
检查线程是否可被 join。检查当前的线程对象是否表示了一个活动的执行线程,由默认构造函数创建的线程是不能被 join 的。另外,如果某个线程 已经执行完任务,但是没有被 join 的话,该线程依然会被认为是一个活动的执行线程,因此也是可以被 join 的。
t.joinable();
native_handle函数
由于 std::thread 的实现和操作系统相关,因此该函数返回与 std::thread 具体实现相关的线程句柄,例如在符合 Posix 标准的平台下(如 Unix/Linux)是 Pthread 库
yield函数
当前线程放弃执行,操作系统调度另一线程继续执行。
std::this_thread::yield();
hardware_concurrency 函数
此函数为静态函数,用于检测硬件并发特性,返回当前平台的线程实现所支持的线程并发数目,但返回值仅仅只作为系统提示(hint)。
条件变量
作为线程同步的重要方法,std::thread,也支持了condition_variable:当某些条件不满足时,停止执行直到该条件被满足。
在经典的生产者消费者模式下,生产者和消费者就是通过condition variable来实现同步的。当有限的生产力无法满足日益增长的消费需求时,消费者进程就会去睡一觉,直到它想要的东西生产出来才醒来。
condition_variable需要和 unique_lock搭配使用。在一个线程调用wait之前,它必须持有unique_lock锁。当wait被调用时,该锁会被释放,线程会陷入沉睡,等待着王子生产者发过来的唤醒信号。当生产者调用同一个condition_variable的 notify_all方法时,所有沉睡在该变量前的消费者会被唤醒,并尝试重新获取之前释放的unique_lock,继续执行下去。(注意这里发生了锁争用,只有一个消费者能够获得锁,其他消费者得等待该消费者释放锁)。如果只想叫醒一个线程,可以用notify_one。
wait可以接受两个参数。此时第二个参数用于判断当前是否要沉睡。
[]{ return msgQueue.size() > 0;});
while (msgQueue.size() <= 0) {
condvar.wait()
}
这里把沉睡的线程比作睡美人,万一王子变成了青蛙,来不及唤醒她,那睡美人不就得睡到天荒地老海枯石烂?
为了解决这个问题,通过wait_until和wait_for,你可以设定线程的等待时间。设置notify_all_at_thread_exit也许能帮得上忙。
atomic
它提供了一组轻量级的、作用在单个变量上的原子操作。atomic位于头文件atomic。内容不会被线程的切换所打断。
/*time:20180605 author:MISAYAONE */
#include<iostream>
#include<thread>
#include<Windows.h>
#include<mutex>
#include<condition_variable>
#include<queue>
using namespace std;
mutex mu_msg;
condition_variable cv_msg;
//消费者,生产者模式的简单实现(利用条件变量和互斥锁)
queue<int> msg_queue;
void producer(int start,int end)
{
for (int i=start;i<end;i++)
{
mu_msg.lock();
msg_queue.push(i);
mu_msg.unlock();
}
cout << "msg produced" << endl;
if (msg_queue.size() > 20)
{
cv_msg.notify_all();//沉睡在该变量上的所有线程都将被唤醒,并尝试获取互斥锁(只有一个消费者可获得互斥锁)
}
}
void consumer(int demand)
{
while (true)
{
unique_lock<std::mutex> ulock(mu_msg);
cv_msg.wait(ulock,[] {return msg_queue.size() > 0;});//尝试获取互斥锁,否则等待
printf("Consume msg %d\n",msg_queue.front());
msg_queue.pop();
--demand;
if (!demand)
{
break;
}
}
}
mutex mu;//互斥锁对象
int num = 100;
void thread_func1()
{
for (int i=0;i<10;i++)
{
cout <<"thread 1's "<< i << endl;
Sleep(100);
}
while (num>0)//这里不能用while,好无知....
{
mu.lock();//互斥锁加锁
cout << "1还在执行" << num << endl;
num--;
mu.unlock();//互斥锁解锁
if (num < 50)
{
//当前线程就不再执行
this_thread::yield();
break;
}
}
}
void thread_func2(int n)
{
for (int i = 0; i<n; i++)
{
cout <<"thread 2's "<< i << endl;
Sleep(200);
}
while (num>0)
{
mu.lock();
cout <<"2还在执行"<< num << endl;
num--;
mu.unlock();
}
}
class A
{
public :
void thread_func3()
{
for (int i = 0; i<10; i++)
{
cout << "class A thread 3's " << i << endl;
Sleep(200);
}
}
};
class thread_guard
{
thread &t;
public:
explicit thread_guard(thread& _t):t(_t){}
~thread_guard()
{
if (t.joinable())
{
t.join();
}
}
//拷贝赋值默认去除
thread_guard(const thread_guard&) = delete;
thread_guard& operator=(const thread_guard&) = delete;
};
int main()
{
A a;
thread task00();//默认构造函数
thread task01(thread_func1);//正常构造函数
thread_guard g(task01);//出现异常后,函数退出,g局部对象对销毁,此时g调用析构函数,会自动执行task01的join函数,从而能够保证join一定会被调用
thread task02(thread_func2,10);//带args的线程构造函数
//thread task_i(move(task02));//转移线程所有权,此时再利用task02调用join和detach会报错
thread task03(&A::thread_func3,a);//传入类的成员函数作为线程构造函数的参数
if (task01.joinable())//此处不可以使用task00线程来判断
{
cout << "task01 is joinable" << endl;
}
//join函数顺序执行线程
task01.join();
task02.join();
//task_i.join();
//task03.join();
//不影响当前代码的执行,几个线程后台自行执行,不阻塞主线程
//task01.detach();
//task02.detach();
//task_i.detach();
task03.detach();
//lambda匿名函数
for (int j=0;j<20;j++)
{
thread t([j]() {cout << j << endl; });
t.detach();
}
for (int i = 0; i<10; i++)
{
cout << "main thread's " << i << endl;
Sleep(200);
}
cout << "task01.get_id() = " << task01.get_id() << endl;//获取线程ID
unsigned int core_num = std::thread::hardware_concurrency();
cout << "cpu 核数" << core_num << endl;
thread mutiple00(producer,10,20);
thread mutiple01(producer,20,30);
thread mutiple02(producer,30,40);
thread mutiple03(consumer,5);
thread mutiple04(consumer,8);
mutiple00.join();
mutiple01.join();
mutiple02.join();
mutiple03.join();
mutiple04.join();
cin.get();
return 0;
}