设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

使用C++11编写Linux多线程程序

2014-12-16 11:23| 发布者: joejoe0332| 查看: 4443| 评论: 0|原作者: 朱广旭|来自: IBM DeveloperWorks

摘要: 多线程可以让我们的应用程序拥有更加出色的性能,同时,如果没有用好,多线程又是比较容易出错的且难以查找错误所在,甚至可以让人们觉得自己陷进了泥潭,希望本文能够帮助您更好地使用 C++11 来进行 Linux 下的多线 ...

  下面我们来看一个简化了的死锁的例子:

清单 19.例子 thread_deadlock.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static mutex g_mutex1, g_mutex2;
static void
inc1(int *p ){
 for(int i = 0; i < COUNT; i++){
 g_mutex1.lock();
 (*p)++;
 g_mutex2.lock();
 // do something.
 g_mutex2.unlock();
 g_mutex1.unlock();
 }
}
static void
inc2(int *p ){
 for(int i = 0; i < COUNT; i++){
 g_mutex2.lock();
 g_mutex1.lock();
 (*p)++;
 g_mutex1.unlock();
 // do other thing.
 g_mutex2.unlock();
 }
}
void threadMutex(void){
 int a = 0;
 thread ta( inc1, &a);
 thread tb( inc2, &a);
 ta.join();
 tb.join();
 cout << "a=" << a << endl;
}

在这个例子中,g_mutex1 和 g_mutex2 都是互斥的资源,任意时刻都只有一个线程可以持有(加锁成功),而且只有持有线程调用 unlock 释放锁资源的时候其它线程才能去持有,满足条件 1 和 3,线程 ta 持有了 g_mutex1 之后,在释放 g_mutex1 之前试图去持有 g_mutex2,而线程 tb 持有了 g_mutex2 之后,在释放 g_mutex2 之前试图去持有 g_mutex1,满足条件 2 和 4,这种情况之下,当线程 ta 试图去持有 g_mutex2 的时候,如果 tb 正持有 g_mutex2 而试图去持有 g_mutex1 时就发生了死锁。在有些环境下,可能要多次运行这个例子才出现死锁,实际工作中这种偶现特性让查找问题变难。要破除这个死锁,我们只要按如下代码所示破除条件 3 和 4 即可:

清单 20.例子 thread_break_deadlock.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static mutex g_mutex1, g_mutex2;
static voi
inc1(int *p ){
 for(int i = 0; i < COUNT; i++){
 g_mutex1.lock();
 (*p)++;
 g_mutex1.unlock();
 g_mutex2.lock();
 // do something.
 g_mutex2.unlock();
 }
}
static void
inc2(int *p ){
 for(int i = 0; i < COUNT; i++){
 g_mutex2.lock();
 // do other thing.
 g_mutex2.unlock();
 g_mutex1.lock();
 (*p)++;
 g_mutex1.unlock();
 }
}
void threadMutex(void){
 int a = 0;
 thread ta( inc1, &a);
 thread tb( inc2, &a);
 ta.join();
 tb.join();
 cout << "a=" << a << endl;
}

  在一些复杂的并行编程场景,如何避免死锁是一个很重要的话题,在实践中,当我们看到有两个锁嵌套加锁的时候就要特别提高警惕,它极有可能满足了条件 2 或者 4。


结束语

上述例子在 CentOS 6.5,g++ 4.8.1/g++4.9 以及 clang 3.5 下面编译通过,在编译的时候,请注意下述几点:

  • 设置 -std=c++11;
  • 链接的时候设置 -pthread;
  • 使用 g++编译链接时设置 -Wl,–no-as-needed 传给链接器,有些版本的 g++需要这个设置;
  • 设置宏定义 -D_REENTRANT,有些库函数是依赖于这个宏定义来确定是否使用多线程版本的。

具体可以参考本文所附的代码中的 Makefile 文件。

在用 gdb 调试多线程程序的时候,可以输入命令 info threads 查看当前的线程列表,通过命令 thread n 切换到第 n 个线程的上下文,这里的 n 是 info threads 命令输出的线程索引数字,例如,如果要切换到第 2 个线程的上下文,则输入命令 thread 2。

聪明地使用多线程,拥抱多线程吧。

参考资料

学习

原文出处: IBM DeveloperWorks - 朱广旭


酷毙

雷人
1

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部