c++11封装了有关多线程编程的类库,使用他们会使多线程编程更为轻松简单,这里就总结一下std::thread的简单实用。
使用std::thread之前我们先来了解有关的函数头和其相关的成员方法
相关的头文件有
相关成员:
thread
//std::thread::id() 比较是否相等
std::thread::hardware_concurrency()这是一个静态成员函数,返回cpu核心数,即能同时并行的数量
std::thread::swap() 交换线程
std::thread::joinnable() 判断是否要等待
std::thread::join() 等待线程结束才能走下一步
std::thread::datach() 切割,使线程成为孤儿线程,主线程死亡不会对其有影响
std::thread::get_id() 得到线程id
std::this_thread::sleep_for() 等待一段时间
std::this_thread::sleep_until() 等待直到某个时间
future(只能移动,不能复制,即默认情况下,在promise和future之间是一对一关系的)
std::future::share() 构造新的shared_future实例,与future的区别是这个能一个关联几个
std::future::wait() 判断有没有返回信息
std::future::wait_for() 判断一段时间内有没有返回信息,没有即算没有返回信息
std::future::wait_until() 判断有没有返回信息,直到某个时间没有即算没有返回
std::future::get() 得到绑定后的线程返回信息
shared_future(这个可以复制,即 std::shared_future 支持了一个一对多的关系,即一个promise多个future。)
std::shared_future::valid() 判断有没有绑定
其他的和future一样
packaged_task(这个和promise的区别是他的形参塞的是函数,promise形参塞得是变量)
std::packaged_task::swap() 交换绑定
std::packaged_task::get_future() 传回信息
std::packaged_task::reset() 更新新的绑定future
std::packaged_task::valid() 判断有没有绑定
std::packaged_task::make_ready_at_thread_exit()
promise(无论是async还是package_task都是将函数返回值作为写入future内容的手段,但很多情况下,设计者希望future只提供读的接口,而暴露出写的接口。这便是promise的目标)
std::promise::swap() 交换绑定对象
std::promise::get_future() 返回结果给future
std::promise::set_value() 将一个值赋予promise,用来返回非future
std::promise::set_value_at_thread_exit() 赋值,等到线程结束后才就绪传回
std::promise::set_exception() 将一个异常的值返回给future
std::promise::set_exception_at_thread_exit() 将一个异常的值返回给future,等到线程结束后才就绪传回
mutex
std::mutex::lock() 上锁
std::mutex::try_lock() 检查是否能上锁,能就上
std::mutex::unlock() 解锁
std::recursive_mutex()递归锁
std::timed_mutex()超时锁
std::recursive_timed_mutex() 超时递归锁
std::lock_guard() 智能锁,不用解锁(类似于RAII)
std::unique_lock::swap() 交换锁
std::unique_lock::lock() 上锁(这个也是智能锁,不用解锁,对比lock_guard多了几个构造函数,更加灵活,开销更大)
std::unique_lock::try_lock()
std::unique_lock::unlock()
std::unique_lock::try_lock_for()
std::unique_lock::try_lock_until()
std::unique_lock::owns_lock() 检查自己本身是否有锁
std::unique_lock::mutex() 返回与*this相关的互斥元,如果有的话
std::unique_lock::release() 返回与*this相关的互斥元,如果有的话,并且释放该关联
condition_variable 与unique_lock连用,阻塞知道某个条件为真
std::notify_one()
唤醒当前正在等待的一个线程
std::notify_all()
唤醒当前正在等待的全部线程
std::wait()
一直等待,直到被唤醒(notify_all(),notify_one())
std::wait_for()
比前面多了个时间段
std::wait_until()
比前面那个多了个伪唤醒
condition_variable_any
这里和condition_variable的区别是前者只能和unique_lock()一起使用,any版本可以与任意锁使用
使用了原子变量atomic就不需要互斥量了,原子变量即是一个变量值得读取修改回写变成一个不可打断的操作,于是我们就有了原子变量。以下是原子变量的用法:
(附:原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程) 原子操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断 )
实例:
#include
#include
#include
#include
#include
#include
//#include
std::mutex mux;
std::recursive_mutex rmux;
void ThreadFun1()
{
{
mux.lock();//加锁
std::cout << "创建线程线程" << std::endl;
mux.unlock();//解锁
}
}
void Lock_GuartFun2()
{
//加锁
std::lock_guard lock(mux);
std::cout << "线程Lock_GuartFun" << std::endl;
}
void Unique_Lock2()
{
std::unique_lock lock(mux);
std::cout << "线程Unique_Lock " ;
lock.unlock();
lock.lock();
std::cout << "刚才我暂时解锁,又上锁了,皮一下很开心" << std::endl;
}
void FuntureFun(std::future &fut)
{
//获取Promise的值
auto val = fut.get();
{
std::unique_lock lock(mux);
//mux.lock(); //多写了这部,直接死锁
std::cout << "获得promise异步线程的秘密参数i,i = " << val << std::endl;
}
}
void Promise(std::promise &pro)
{
int i = 10;
{
mux.lock();
std::cout << "给promise赋值,发送给FuntureFun异步线程i的值" << std::endl;
mux.unlock();
}
pro.set_value(i);//赋值
}
class TF
{
public:
//重载()
TF &operator()()
{
{
mux.lock();
std::cout << "我是一个伪函数,为了测试创建线程里放个类" << std::endl;
mux.unlock();
}
return *this;
}
};
int RecursiveMutex()
{
static int i = 0;
{
//std::lock_guard lock(mux); //使用这个锁就会死锁
std::lock_guard lock(rmux);//加递归锁
std::cout << "我是一个递归函数, 递归了" << i << std::endl;
++i;
}
return i < 5 ? RecursiveMutex() : 0;
}
int main()
{
TF f;
std::future fut;//事实上,保存函数指针,类指针什么的都可以例子:
std::promise pro;
fut = pro.get_future();//绑定
std::thread MyThread1(ThreadFun1);
std::thread MyThread2([]() {mux.lock(); std::cout << "我是一个lambda" << std::endl; mux.unlock(); });
std::thread MyThread3(f);
std::thread MyThread4(Lock_GuartFun2);
std::thread MyThread5(Unique_Lock2);
std::thread MyThread6(Promise,std::ref(pro));//传引用要用类似c#的写法
std::thread MyThread7(FuntureFun, std::ref(fut));//注意,future在收到值之前会一直堵塞,直到收到值。
std::thread MyThread8(RecursiveMutex);
MyThread1.join();
MyThread2.join();
MyThread3.join();
MyThread4.join();
MyThread5.join();
MyThread6.join();
MyThread7.join();
MyThread8.join();//等待线程结束后再执行剩下的
std::cout << "线程并行数 = " << MyThread1.hardware_concurrency() << std::endl;
std::cout << "MyThread1线程id = " << MyThread1.get_id() << std::endl;
system("pause");
return 0;
}
结果:
最后粘上一些总结的很不错的网站:
https://www.jianshu.com/p/c1dfa1d40f53
c++11-----多线程
10分钟带你掌握多线程