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 中的新的基础设施(主要是多线程.锁.条件变量)来阐述一个经典问题——生产者消费者模型,并给出 ...
随机推荐
- CentOS 6.3下部署LVS(NAT模式)+keepalived实现高性能高可用负载均衡
一.简介 VS/NAT原理图: 二.系统环境 实验拓扑: 系统平台:CentOS 6.3 Kernel:2.6.32-279.el6.i686 LVS版本:ipvsadm-1.26 keepalive ...
- UITableView划动删除的实现
对于app应用来说,使用列表的形式展现数据非UITableView莫属.在熟练掌握了用UITableView展示数据以后,是不是也遇到了需要删除数据的需求?是不是觉得在一行数据上划动一下,然后出现一个 ...
- 《C++ Primer Plus》14.2 私有继承 学习笔记
C++(除了成员变量之外)还有另一种实现has-a关系的途径——私有继承.使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员.(如果使用保护继承,基类的公有成员和保护成员都将称为派生类的保 ...
- iOS-利用插件实时刷新模拟器(提高效率)
解决办法: 1.需要给Xcode安装一个Alcatraz插件 安装完成后:点击window 下面的 package manager 安装我们今天的主角 2. ‘Injection Plugin for ...
- c++11——右值引用
1. 左值和右值 左值是表达式结束之后仍然存在的持久化对象,而右值是指表达式结束时就不再存在的临时对象. c++11中,右值分为两种类型:将亡值(xvalue, expiring value) ...
- Neutron SDN 手动实现手册
安装架构介绍 本文旨在通过自己搭建类似neutron (openvswitch + gre) 实现SDN 的环境,学习了解其工作原理,模拟核心原理,比如:同一租户自定义网络 instance 互通,手 ...
- LeetCode - Duplicate Emails
Description:Write a SQL query to find all duplicate emails in a table named Person. 找出表中重复的Email. # ...
- SQL中 decode()函数简介(转载)
今天看别人的SQL时看这里面还有decode()函数,以前从来没接触到,上网查了一下,还挺好用的一个函数,写下来希望对朋友们有帮助哈! decode()函数简介: 主要作用:将查询结果翻译成其他值(即 ...
- postgresql----SELECT
示例1.简单查询 使用*查询表所有的字段,也可以指定字段名查询 test=# select * from tbl_insert; a | b ---+---- | sd | ff ( rows) te ...
- try...finally的妙用
受博文 C#中Finally的一个不太常见的用法 的启发,正好在开发中遇到这样一段代码: public bool ChangeBlogApp(Guid userID, string oldBlogAp ...