C++11 多线程

来源:互联网 发布:cms搜索不到ip 编辑:程序博客网 时间:2024/05/17 08:33
新特性之描述:
虽然 C++11 会在语言的定义上提供一个内存模型以支持线程,但线程的使用主要将以 C++11 标准库的方式呈现。
C++11 标准库会提供类型 thread (std::thread)。若要运行一个线程,可以创建一个类型 thread 的实体,其初始参数为一个函数对象,以及该函数对象所需要的参数。通过成员函数 std::thread::join() 对线程会合的支持,一个线程可以暂停直到其它线程运行完毕。若有底层平台支持,成员函数 std::thread::native_handle() 将可提供对原生线程对象运行平台特定的操作。
对于线程间的同步,标准库将会提供适当的互斥锁 (像是 std::mutex,std::recursive_mutex 等等) 和条件参数 (std::condition_variable 和 std::condition_variable_any)。前述同步机制将会以 RAII 锁 (std::lock_guard 和 std::unique_lock) 和锁相关算法的方式呈现,以方便程序员使用。
对于要求高性能,或是极底层的工作,有时或甚至是必须的,我们希望线程间的通信能避免互斥锁使用上的开销。以原子操作来访问内存可以达成此目的。针对不同情况,我们可以通过显性的内存屏障改变该访问内存动作的可见性。

对于线程间异步的传输,C++11 标准库加入了 以及 std::packaged_task 用来包装一个会传回异步结果的函数调用。 因为缺少结合数个 future 的功能,和无法判定一组promise 集合中的某一个 promise 是否完成,futures 此一提案因此而受到了批评。

更高级的线程支持,如线程池,已经决定留待在未来的 Technical Report 加入此类支持。更高级的线程支持不会是 C++11 的一部份,但设想是其最终实现将创建在目前已有的线程支持之上。
std::async 提供了一个简便方法以用来运行线程,并将线程绑定在 std::future。用户可以选择一个工作是要多个线程上异步的运行,或是在一个线程上运行并等待其所需要的数据。默认的情况,实现可以根据底层硬件选择前面两个选项的其中之一。另外在较简单的使用情形下,实现也可以利用线程池提供支持。

具体细节:

C++标准线程库简洁且强大,跨平台显得毫无压力可言。这么好用的东西,为什么不赶快试试呢?

要使用标准线程库需要包括头文件
#include <thread>
#include <mutex>
#include <condition_variable>

这三个头文件涵盖了新标准的大部分内容,完全可以满足项目的需求,C++线程库源自boost,大部分内容都非常接近。

//非常简单不是么?
void run()
{
std::cout<<"Hello C++ Thread!"<<std::endl;

std::chrono::duration<int> a(5);// 睡眠持续5秒
std::this_thread::sleep_for(a);

std::cout<<"waked up"<<std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{

std::thread t(run);// 初始化新的线程,run为传递的回调函数

t.join(); // 阻塞主线程,直到线程t完成所有操作

return 0;
}

极具魅力与诱惑的存在,封装的实在是太好了,使用起来非常的简洁方便。

多线程不可避免的需要谈到互斥锁,C++新标准自带了4种互斥锁,实现方法大同小异,下面赶快来看看。

std::mutex iomutex;
std::recursive_mutex;
std::timed_mutex tmutex;
std::recursive_timed_mutex;

具体实现:
std::mutex iomutex;

void run()
{
iomutex.lock();// 当全局互斥锁iomutex被锁定时,其它请求线程进入阻塞队列等待

std::cout<<"Hello C++ Thread!"<<std::endl;

std::chrono::milliseconds a(5000);// 睡眠持续5秒
std::this_thread::sleep_for(a);

std::cout<<"waked up"<<std::endl;

iomutex.unlock();
}

int _tmain(int argc, _TCHAR* argv[])
{

std::thread t1(run);// 初始化新的线程,run为传递的回调函数
std::thread t2(run);

t1.join(); // 阻塞主线程,直到线程t完成所有操作
t2.join();

return 0;
}

再来说下递归锁std::recursive_mutex,递归锁的用途只是因为在临界区内部的函数中也有锁的操作,因为项目模块分工,你不知道你的队友是不是也使用相同的互斥锁,如果这种情况发生的话,悲剧当然就是死锁啦!不过引入递归锁,这个问题就引刃而解了,不过麻烦的是锁与解锁需要匹配,这个是一定要注意的。

超时锁std::timed_mutex tmutex的用途是为了抢占,因为当一个线程进行临界区操作的时候,你不知道它在做什么?如果时间花费非常长呢?超时锁可以在指定时间内抢占资源。

std::chrono::duration<int> a(5);
tmutex.try_lock_for(a);//超时时间设为5秒

// 临界区

tmutex.unlock();

最后说一下条件变量condition_variable,作用是为了线程之间的通信操作,比如A线程需要等待B线程完成某项操作才会继续执行,这时候A线程需要等待B线程的通知。
这时候使用条件变量来处理,是最不好不过的了。

std::mutex cmutex;
std::condition_variable con_var;

void run1()
{
std::unique_lock<std::mutex> locker(cmutext);
con_var.wait(locker);
}

void run2()
{
if(某项条件成立)
{
con_var.notify_all();//通知所有等待线程恢复执行
}
}
0 0