C++11多线程教学
转自:http://www.cnblogs.com/lidabo/p/3908705.html
本篇教学代码可在GitHub获得:https://github.com/sol-prog/threads。
在之前的教学中,我展示了一些最新进的C++11语言内容:
- 1. 正则表达式(http://solarianprogrammer.com/2011/10/12/cpp-11-regex-tutorial/)
- 2. raw string(http://solarianprogrammer.com/2011/10/16/cpp-11-raw-strings-literals-tutorial/)
- 3. lambda(http://solarianprogrammer.com/2011/11/01/cpp-11-lambda-tutorial/)
也许支持多线程是C++语言最大的变化之一。此前,C++只能利用操作系统的功能(Unix族系统使用pthreads库),或是例如OpenMP和MPI这些代码库,来实现多核计算的目标。
本教程意图让你在使用C++11线程上起个头,而不是只把语言标准在这里繁复地罗列出来。
创建和启动一条C++线程就像在C++源码中添加线程头文件那么简便。我们来看看如何创建一个简单的带线程的HelloWorld:
#include《iostream》
#include《thread》
//This function will be called from a thread
//该函数将在一条线程中得到调用
void call_from_thread() {
std::cout << "Hello, World" << std::endl;
}
int main() {
//Launch a thread
//启动一条线程
std::thread t1(call_from_thread);
//Join the thread with the main thread
//和主线程协同
t1.join();
return 0;
}
在Linux系统中,上列代码可采用g++编译:
g++ -std=c++0x -pthread file_name.cpp
在安装有Xcode4.x的麦金系统上,可用clang++编译上述代码:
clang++ -std=c++0x -stdlib=libc++ file_name.cpp
视窗系统上,可以利用付费代码库,just::thread,来编译多线程代码。但是很不走运,他们没有提供代码库的试用版,我做不了测试。
在真实世界的应用程序中,函数“call_from_thread”相对主函数而言,独立进行一些运算工作。在上述代码中,主函数创建一条线程,并在t1.join()处等待t1线程运行结束。如果你在编码中忘记考虑等待一条线程结束运行,主线程有可能抢先结束它自己的运行状态,整个程序在退出的时候,将杀死先前创建的线程,不管函数“call_from_thread”有没有执行完。
上面的代码比使用POSIX线程的等价代码,相对来说简洁一些。请看使用POSIX线程的等价代码:
//This function will be called from a thread
void *call_from_thread(void *) {
std::cout << "Launched by thread" << std::endl;
return NULL;
}
int main() {
pthread_t t;
//Launch a thread
pthread_create(&t, NULL, call_from_thread, NULL);
//Join the thread with the main thread
pthread_join(t, NULL);
return 0;
}
我们通常希望一次启动多个线程,来并行工作。为此,我们可以创建线程组,而不是在先前的举例中那样创建一条线程。下面的例子中,主函数创建十条为一组的线程,并且等待这些线程完成他们的任务(在github代码库中也包含这个例子的POSIX版本):
...
static const int num_threads = 10;
...
int main() {
std::thread t[num_threads];
//Launch a group of threads 启动一组线程
for (int i = 0; i < num_threads; ++i) {
t[i] = std::thread(call_from_thread);
}
std::cout << "Launched from the mainn";
//Join the threads with the main thread
for (int i = 0; i < num_threads; ++i) {
t[i].join();
}
return 0;
}
记住,主函数也是一条线程,通常叫做主线程,所以上面的代码实际上有11条线程在运行。在启动这些线程组之后,线程组和主函数进行协同(join)之前,允许我们在主线程中做些其他的事情,在教程的结尾部分,我们将会用一个图像处理的例子来说明之。
在线程中使用带有形参的函数,是怎么一回事呢?C++11允许我们在线程的调用中,附带上所需的任意参数。为了举例说明,我们可以修改上面的代码,以接受一个整型参数(在github代码库中也包含这个例子的POSIX版本):
static const int num_threads = 10;
//This function will be called from a thread
void call_from_thread(int tid) {
std::cout << "Launched by thread " << tid << std::endl;
}
int main() {
std::thread t[num_threads];
//Launch a group of threads
for (int i = 0; i < num_threads; ++i) {
t[i] = std::thread(call_from_thread, i);
}
std::cout << "Launched from the mainn";
//Join the threads with the main thread
for (int i = 0; i < num_threads; ++i) {
t[i].join();
}
return 0;
}
在我的系统上,上面代码的执行结果是:
Sol$ ./a.out
Launched by thread 0
Launched by thread 1
Launched by thread 2
Launched from the main
Launched by thread 3
Launched by thread 5
Launched by thread 6
Launched by thread 7
Launched by thread Launched by thread 4
8L
aunched by thread 9
Sol$
能看到上面的结果中,程序一旦创建一条线程,其运行存在先后秩序不确定的现象。程序员的任务就是要确保这组线程在访问公共数据时不要出现阻塞。最后几行,所显示的错乱输出,表明8号线程启动的时候,4号线程还没有完成在stdout上的写操作。事实上假定在你自己的机器上运行上面的代码,将会获得全然不同的结果,甚至是会输出些混乱的字符。原因在于,程序内的11条线程都在竞争性地使用stdout这个公共资源(案:Race Conditions)。
要避免上面的问题,可以在代码中使用拦截器(barriers),如std:mutex,以同步(synchronize)的方式来使得一群线程访问公共资源,或者,如果可行的话,为线程们预留下私用的数据结构,避免使用公共资源。我们在以后的教学中,还会讲到线程同步问题,包括使用原子操作类型(atomic types)和互斥体(mutex)。
从原理上讲,编写更加复杂的并行代码所需的概念,我们已经在上面的代码中都谈到了。
如果有兴趣学习新的C++11语法,我建议阅读《Professional C++》,或《C ++ Primer Plus》。C++11多线程主题方面,建议阅读《C++ Concurrency in Action》,这是一本好书。
C++11多线程教学的更多相关文章
- C++11多线程教学(二)
C++11多线程教学II 从我最近发布的C++11线程教学文章里,我们已经知道C++11线程写法与POSIX的pthreads写法相比,更为简洁.只需很少几个简单概念,我们就能搭建相当复杂的处理图片程 ...
- C++11多线程教学(一)
本篇教学代码可在GitHub获得:https://github.com/sol-prog/threads. 在之前的教学中,我展示了一些最新进的C++11语言内容: 1. 正则表达式(http://s ...
- C++11多线程教学II
从我最近发布的C++11线程教学文章里,我们已经知道C++11线程写法与POSIX的pthreads写法相比,更为简洁.只需很少几个简单概念,我们就能搭建相当复杂的处理图片程序,但是我们回避了线程同步 ...
- c++ 11 多线程教学(1)
本篇教学代码可在GitHub获得:https://github.com/sol-prog/threads. 在之前的教学中,我展示了一些最新进的C++11语言内容: 1. 正则表达式(http://s ...
- C++11 多线程 教学(2)
C++11开始支持多线程编程,之前多线程编程都需要系统的支持,在不同的系统下创建线程需要不同的API如pthread_create(),Createthread(),beginthread()等, ...
- 【转】C++ 11 并发指南一(C++ 11 多线程初探)
引言 C++ 11自2011年发布以来已经快两年了,之前一直没怎么关注,直到最近几个月才看了一些C++ 11的新特性,算是记录一下自己学到的东西吧,和大家共勉. 相信Linux程序员都用过Pthrea ...
- C++11 并发指南一(C++11 多线程初探)
引言 C++11 自2011年发布以来已经快两年了,之前一直没怎么关注,直到最近几个月才看了一些 C++11 的新特性,今后几篇博客我都会写一些关于 C++11 的特性,算是记录一下自己学到的东西吧, ...
- C++11 多线程编程 使用lambda创建std::thread (生产/消费者模式)
要写个tcp server / client的博客,想着先写个c++11多线程程序.方便后面写博客使用. 目前c++11中写多线程已经很方便了,不用再像之前的pthread_create,c++11中 ...
- C++11 并发指南九(综合运用: C++11 多线程下生产者消费者模型详解)
前面八章介绍了 C++11 并发编程的基础(抱歉哈,第五章-第八章还在草稿中),本文将综合运用 C++11 中的新的基础设施(主要是多线程.锁.条件变量)来阐述一个经典问题——生产者消费者模型,并给出 ...
随机推荐
- JSON.parse()和JSON.stringfy()
JSON.parse()从字符串中解析出JSON对象: var data = '{"a":1,"b":2}'; JSON.parse(data); JSON.s ...
- Swift-属性、方法、下标
存储属性和计算属性 类.结构和枚举都能够定义存储属性和计算属性.其中存储属性就是常见的形式,又分为变量属性和常量属性,如: struct Point { var x = 0.0, y = 0.0 } ...
- C# Timer自带定时器
官方文档 https://msdn.microsoft.com/zh-cn/library/system.timers.timer.aspx using System; using System.Ti ...
- TP框架控制器的空操作
在浏览器中输入tp框架入口文件的地址,如图 要注意,localhost/后面跟的是www的下一级,tp文件的上一级,因为我直接把tp文件做成了www目录的下一级,所以我写的地址localhost后面跟 ...
- Thinkphp3.2 PHPexcel 导出
1 下载phpexecl 放入到tp里边. 路径如下:项目根目录\ThinkPHP\Library\Org\Util 2 PHP 代码部分 封装一个方法 private function getE ...
- JS-JavaScript类库整理 [更新中...]
老大.jQuery插件库 ——收集最全最新最好的jQuery插件 http://www.jq22.com/ 一.Moment.js ——JavaScript 日期处理类库 http://momentj ...
- Suricata规则配置
Suricata 规则配置 IDS/IPS/WAF IPS.IDS和WAF分别是入侵防御系统和入侵检测系统以及WEB应用防火墙的简称,很多人说这些玩意不就是盒子吗已经过时了,其实不是,SIEM其实是有 ...
- 【BZOJ1030】[JSOI2007]文本生成器 AC自动机+动态规划
[BZOJ1030][JSOI2007]文本生成器 Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文 ...
- apache工作模式worker以及prefork的切换
apache比较常用的工作模式有worker以及prefork两种方式. 如果在编译时候不指定,系统默认的是prefork模式:如果需要换成worker模式,需要在编译的时候带上编译参数:--with ...
- 理解 php new static
今天在看 Laravel 的容器(Container)实现时,发现了这么一段突然不能理解的代码: ** * Set the globally available instance of the con ...