c++11 线程:让你的多线程任务更轻松
来源:互联网 发布:网络诈骗主犯 编辑:程序博客网 时间:2024/06/13 09:30
c++11 线程:让你的多线程任务更轻松
介绍
本文旨在帮助有经验的Win32程序员来了解c++ 11线程库及同步对象 和 Win32线程及同步对象之间的区别和相似之处。
在Win32中,所有的同步对象句柄(HANDLE)是全局句柄.它们可以被共享,甚至可以在进程间复制。在C++11中,所有的同步对象都是栈(stack)对象,这意味着它们必须是可“分离(detached)”的(如果支持“分离”的话)以便能够被栈框架(stack frame)所析构。如果大量对象应该分离而你没有,那么它们便会无法实现自己的行动,而毁掉你的原本计划。(译者注:在pthread中,线程有joinable和unjoinable之分,具有joinable的线程在线程结束时,不会清空该线程所占用的栈空间,通常的做法是在pthrea_create创建线程后,再调用pthread_join(有点waitforsingleobject的意思)才会清空,而unjoinable的属性的线程在线程结束时,就会自动清空所占用空间)
所有的c++11同步对象都有一个native_handle()成员,它返回具体实现句柄(在win32,它就是一个handle)
在我的所有例子,我给出了win32伪代码。祝你愉快!
背景知识
ox0000000.木有 :D。我也是c++11线程的新手。你需要自己去了解win32同步相关知识。这里可能不是合适的同步技术的教程,而是一个C++11机制的快速引导,以便对你所指定的计划有所帮助。
简单成就完美
一个简单例子:启动一个线程,然后等它结束:
1
void
foo()
2
{
3
}
4
void
func()
5
{
6
std::
thread
t(foo);
// Starts. Equal to CreateThread.
7
t.join();
// Equal to WaitForSingleObject to the thread handle.
8
}
与win32线程不同,你可以在这里传递参数:
1
void
foo(
int
x,
int
y)
2
{
3
// x = 4, y = 5.
4
}
5
void
func()
6
{
7
std::
thread
t(foo,4,5);
// Acceptable.
8
t.join();
9
}
这样,通过传递‘this’指针给std::thread让成员函数成为一个线程,变成了一件很简单的事情.如果std::thread得以析构,而你没有调用join(),它将会异常终止。脱离c++封装运行线程:
1
void
foo()
2
{
3
}
4
void
func()
5
{
6
std::
thread
t(foo);
7
// 在这里已经调用了detach方法,c++对象从win32对象中脱离出来,如果此时还调用join方法,就会抛出std::system_error()
8
t.detach();
9
}
除了join(),detach()方法,还有joinable(),get_id(),sleep_for(),sleep_until().它们都是自解释的,很好理解。
使用互斥(Mutex)
std::mutex与win32的临界区(cirtical section)很类似。lock()如同EnterCriticalSection,unlock如同LeaveCriticalSection,try_lock则像TryEnterCriticalSection。
01
std::mutex m;
02
int
j = 0;
03
void
foo()
04
{
05
m.lock();
// 进入临界区域
06
j++;
07
m.unlock();
// 离开
08
}
09
void
func()
10
{
11
std::
thread
t1(foo);
12
std::
thread
t2(foo);
13
t1.join();
14
t2.join();
15
// j = 2;
16
}
嗨,不要走开哦。前面提到不能对std::mutex重复lock。这里有std::recursive_mutex(谁发明的这名字),它的行为则与临界区(critical section)相似,可以重复lock。
1
std::recursive_mutex m;
2
void
foo()
3
{
4
m.lock();
5
m.lock();
// now valid
6
j++;
7
m.unlock();
8
m.unlock();
// don't forget!
9
}
C++11 Thread的线程本地存储(Thread Local Storage)
与TLS(thread local storage)类似,该功能允许你声明一个带有thread_local的声明符的变量。这意味着,每一个线程都有自己的该全局变量的实例(instance),该实例的变量名就是全局变量名称。
以前:
01
int
j = 0;
02
void
foo()
03
{
04
m.lock();
05
j++;
06
m.unlock();
07
}
08
void
func()
09
{
10
j = 0;
11
std::
thread
t1(foo);
12
std::
thread
t2(foo);
13
t1.join();
14
t2.join();
15
// j = 2;
16
}
01
thread_local
int
j = 0;
02
void
foo()
03
{
04
m.lock();
05
j++;
// j is now 1, no matter the thread. j is local to this thread.
06
m.unlock();
07
}
08
void
func()
09
{
10
j = 0;
11
std::
thread
t1(foo);
12
std::
thread
t2(foo);
13
t1.join();
14
t2.join();
15
// j still 0. The other "j"s were local to the threads
16
}
神秘的变量
条件变量(Conditional variables)是能够使线程等待特定条件的对象。在window系统里,这些对象属于用户模式(usr-mode),因而不能被其他进程所共享。在window系统,条件变量与临界区(critical section)有关,用来获取或者释放一个锁。std::condition_variable与std::mutex联用,也是这个原因。
01
std::condition_variable c;
02
// 我们使用mutex而不是recursive_mutex是因为该锁需要一次性获取和释放
03
std::mutex mu;
// We use a mutex rather than a recursive_mutex because the lock has to be acquired only and exactly once.
04
void
foo5()
05
{
06
std::unique_lock lock(mu);
// Lock the mutex
07
c.notify_one();
// WakeConditionVariable. It also releases the unique lock 等待条件变量,它也会释放unque lock
08
}
09
void
func5()
10
{
11
std::unique_lock lock(mu);
// Lock the mutex
12
std::
thread
t1(foo5);
13
// 等价与SleepConditionVariableCS,它解锁mutex 变量nu,并允许foo5来加锁
14
c.wait(lock);
// Equal to SleepConditionVariableCS. This unlocks the mutex mu and allows foo5 to lock it
15
t1.join();
16
}
这并不像看上去那么简单。c.wait() 可能会返回,即使c.notify_one()没有被调用(已知的这种情况是spurious wakeup - http://msdn.microsoft.com/en-us/library/windows/desktop/ms686301(v=vs.85).aspx)。通常,在Vista及以上操作系统,条件变量才被支持。
未来的承诺
设想这样的情况,你希望一个线程做一些事情,然后返回你一个结果。同时,你在做一些其他的工作,该工作也许会也许不会花费你一点时间。你希望在某个特定的时间获取那个线程的结果。
在win32中,你可以这样
- 用CreateThread启动线程
- 在线程里,启动任务,当准备完毕后发送一个事件(event),并把结果放在全局变量里。
- 在主函数里(main)做其它的事情,然后在你想要结果的地方,调用WaitForSingleObject
在c++11,这个可以轻松被std::future实现,然后返回任何类型,因为它是一个模板。
01
int
GetMyAnswer()
02
{
03
return
10;
04
}
05
int
main()
06
{
07
std::future<
int
> GetAnAnswer = std::async(GetMyAnswer);
// GetMyAnswer starts background execution
08
int
answer = GetAnAnswer.get();
// answer = 10;
09
// If GetMyAnswer has finished, this call returns immediately.
10
// If not, it waits for the thread to finish.
11
}
01
std::promise<
int
> sex;
02
void
foo()
03
{
04
// do stuff
05
// 在下面的调用之后,future::get()将会返回该值
06
sex.set_value(1);
// After this call, future::get() will return this value.
07
08
// 调用之后,future::get()将会抛出这个异常
09
sex.set_exception(std::make_exception_ptr(std::runtime_error(
"TEST"
)));
10
}
11
int
main()
12
{
13
future<
int
> makesex = sex.get_future();
14
std::
thread
t(foo);
15
16
// do stuff
17
try
18
{
19
makesex.get();
20
hurray();
21
}
22
catch
(...)
23
{
24
// She dumped us :(
25
}
26
}
代码
附上的代码包含所有上述我的所述。可以在visualstudio 2012 CTP版本的编译器下编译成功(除了tls机制)。(代码地址:http://www.codeproject.com/KB/cpp/540912/c11threads.zip)
还有什么
还有很多值得包括的事情,如:- 信号量(Semaphores)
- 命名对象 (Named objects)
- 进程共享对象 (Shareable objects across processes.)
- ...
你应该做什么呢?通常当编写新的代码,如果足够适用,尽量选择C++标准。对于已存在的代码,我尽量保持使用win32调用,当需要移植它们到另外的平台,我则会用c++11函数来实现CreateThread、SetEvent 等等。
祝你好运!
转自:http://www.oschina.net/translate/cplusplus-11-threading-make-your-multitasking-life
原文地址:http://www.codeproject.com/Articles/540912/Cplusplus-11-Threading-Make-your-multitasking-life
- c++11 线程:让你的多线程任务更轻松
- c++11 线程:让你的多线程任务更轻松
- c++11 线程:让你的多线程任务更轻松
- c++11 线程:让你的多线程任务更轻松
- c++11 多线程:让你的多线程任务更轻松
- [转] c++11 线程:让你的多线程任务更轻松
- Java 开发实践 多线程编程 让你的任务更快更轻松
- 让你的Excel更精彩 让你的工作更轻松
- spring-android的使用(让你更轻松的Auth)
- 简单几步,让你的编程更轻松
- 文件缓存的工具类,让你开发更轻松
- RSS阅读器让你生活更轻松
- 计算合式公式(wff) 【让你的离散作业变的更轻松】
- MyEclipse7.1 下jad插件安装----让你的开发更轻松、方便
- C/C++ volatile让你看的更明白
- C/C++ volatile让你看的更明白
- (转)C/C++ volatile让你看的更明白
- 全面了解ADSL,让你上网更轻松
- win7的vmware中安装ubuntu 13.04看不到共享目录
- 颜色表大全 颜色中英文对照表
- CFStringRef CFSTR与和NSString
- (个人笔记) swing 设置程序级快捷键 和 窗口集快捷键
- 如何跳出当前的多重循环?
- c++11 线程:让你的多线程任务更轻松
- Python正则表达式--前向界定符
- mac下 eclipse支持magic mouse/Trackpad 操作
- CAEmitterLayer(粒子系统)学习笔记(含Demo)
- hibernate中save()和persist()
- SortedList
- yii 修改模块使用的布局文件
- AndroidManifest.xml之<uses-sdk> manifest element详解
- XML中大于号和小于号的写法