12.8    多线程

之前,总是让程序的主线程只创建一个线程。这节将演示怎样在同一个程序中创建多个线程,然后怎样以不同于其启动顺序将它们合并在一起。此外,还演示多线程编程时easy出现的时序问题.
编敲代码thread8.c

/*************************************************************************> File Name:    thread8.c> Description:  thread8.c程序创建多个线程。然后以不同于启动顺序将它们合并在一起> Author:       Liubingbing> Created Time: 2015年07月07日 星期二 19时37分45秒> Other:        thread8.c程序存在一个小漏洞,假设主线程执行足够快时,可能改动传递引用的參数thread_index,造成问题.见thread8a.c************************************************************************/#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>#define NUM_THREADS 6void *thread_function(void *arg);int main(){int res;pthread_t a_thread[NUM_THREADS];void *thread_result;int thread_index;for (thread_index = 0; thread_index < NUM_THREADS; thread_index++) {/* pthread_create创建新线程,这里创建了一个线程ID的数组 */res = pthread_create(&(a_thread[thread_index]), NULL, thread_function, (void *)&thread_index);if (res != 0) {perror("Thread creation failed");exit(EXIT_FAILURE);}sleep(1);}printf("Waiting for threads to finish...\n");/* 主线程中等待合并这些子线程,但并非以创建它们的顺序来合并 */for (thread_index = NUM_THREADS - 1; thread_index >= 0; thread_index--) {res = pthread_join(a_thread[thread_index], &thread_result);if (res == 0) {printf("Picked up a thread\n");} else {perror("pthread_join failed");}}printf("All done\n");exit(EXIT_SUCCESS);
}void *thread_function(void *arg) {int my_number = *(int *)arg;int rand_num;printf("thread_function is running. Argument was %d\n", my_number);/* 创建的线程等待一段随机的时间退出执行 */rand_num = 1 + (int)(9.0 * rand() / (RAND_MAX + 1.0));sleep(rand_num);printf("Bye from %d\n", my_number);pthread_exit(NULL);
}

执行thread8.c,看到例如以下结果:

这个程序首先创建一个线程ID的数组。例如以下所看到的:

pthread_t a_thread[NUM_THREADS];

然后通过循环创建多个线程。例如以下所看到的:

for (thread_index = 0; thread_index < NUM_THREADS; thread_index++) {res = pthread_create(&(a_thread[thread_index]), NULL, thread_function, (void *)&thread_index);
}

创建出的线程等待一段随机的时间后退出执行,例如以下所看到的:

void *thread_function(void *arg) {int my_number = *(int *) arg;int rand_num;printf("thread_function is running. Argument was %d\n", my_number);rand_num = 1 + (int)(9.0 * rand() / RAND_MAX + 1.0));sleep(rand_num);printf("Bye from %d\n", my_number);pthread_exit(NULL);
}

在主线程中。等待合并这些子线程。但并非以创建它们的顺序来合并。例如以下所看到的:

for (thread_index = NUM_THREADS -1; thread_index >= 0; thread_index--) {res = pthread_join(a_thread[thread_index], &thread_result);...
}

这个程序有一个小漏洞,假设将sleep调用从启动线程的循环中删除,它将会变得非常明显。

非常可能会看到一些奇怪的现象,比方一些线程以同样的參数被启动,类似下图:

为什么会出现这种问题?启动线程时,线程函数的參数是一个局部变量,这个变量在循环中被更新。引起问题的代码行是:

for (thread_index = 0; thread_index < NUM_THREADS; thread_index++) {res = pthread_create(&(a_thread[thread_index]), NULL, thread_function, (void *)&thread_index);
}

假设主线程执行的足够快(由于删除sleep(1)之后,主线程相对新线程就很快了),就可能改变某些线程的參数(即thread_index)。

此时,传递引用不是恰当的选择,而传值是正确的.当对共享变量和多个执行路径没有做到足够重视时,程序就可能出现这种错误行为。

编写线程程序时须要在设计上特别小心。

要改正这个问题。能够直接传递给这个參数的值,例如以下所看到的:

res = pthread_create(&(a_thread[thread_index]), NULL, thread_function, (void *)thread_index);

还有改动thread_function函数,例如以下所看到的:

int my_number = (int) arg;

linux程序设计——多线程(第十二章)相关推荐

  1. 《Kotlin 程序设计》第十二章 Kotlin的多线程:协程(Coroutines)

    第十二章 Kotlin的多线程:协程(Coroutines) Kotlin 1.1 introduced coroutines, a new way of writing asynchronous, ...

  2. 韦东山 IMX6ULL和正点原子_「正点原子Linux连载」第十二章官方SDK移植试验

    1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南> 关注官方微信号公众号,获取更多资料:正点原子 第十二章官方SDK移植试验 在上一章中, ...

  3. 【正点原子Linux连载】第二十二章 AP3216C 摘自【正点原子】I.MX6U嵌入式Qt开发指南V1.0.2

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 3)全套实验源码+手册+视频下载地址: ...

  4. 【Linux命令】《鸟哥Linux基础》第十二章 学习shell脚本

    第十二章 学习shell脚本 通常利用shell脚本完成服务器的检测工作,不涉及大量运算. 12.1 简单shell脚本介绍 12.2 简单shell脚本练习 12.2.1 简单范例 范例1:永远的开 ...

  5. linux系统日志_第十二章:走进Linux世界——系统日志管理,日志轮转。

    1.关心问题:哪类程序---> 产生的什么日志----> 放到什么地方 2.处理日志的进程 (1) 第一类: rsyslogd: 系统专职日志程序. 处理绝大部分日志记录, 系统操作有关的 ...

  6. go程序设计语言第十二章-反射

    the go programming language Go提供一种机制,能够在运行时更新变量.查看它们的值,调用它们的方法和它们内在的操作,所有的这些都不需要在编译时知道它们的类型.这种机制就叫做反 ...

  7. Linux系统:第十二章:AWS服务器X86架构安装配置Mysql与MongoDB

    sudo passwd root root su root cd /usr/local/ chmod 777 /usr/local/ 上传文件到/usr/local下 安装MongoDB (安装文件: ...

  8. 鸟哥的Linux私房菜(服务器)- 第十二章、网络参数控管者: DHCP 服务器

    第十二章.网络参数控管者: DHCP 服务器 最近更新日期:2011/07/27 想象两种情况:(1)如果你在工作单位使用的是笔记本电脑,而且常常要带着你的笔记本电脑到处跑, 那么由第四章.连上 In ...

  9. linux i2c adapter 增加设备_「正点原子Linux连载」第六十二章Linux SPI驱动实验(一)...

    1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南>关注官方微信号公众号,获取更多资料:正点原子 第六十二章Linux SPI驱动实验 上一 ...

  10. Linux云计算【第一阶段】第十二章:网络管理、进制及SSH管理与攻防

    第十二章:网络管理及SSH管理与攻防 [重难点] 一.网络发展概述 局域网 城域网 广域网 基本网络协议 客户端与服务器的概念 从客户端到服务器的经过 No.1 客户端与服务器的概念 客户端: 即表示 ...

最新文章

  1. 2019.01-02 总结
  2. 交换机应用寻找10个完美的因素
  3. HDFS小文件问题及解决方案
  4. [15] 星星(Star)图形的生成算法
  5. Win平台使用cmake工具生成sln工程示例
  6. 知识图谱 (知识计算推理)
  7. ABAP 选择屏幕上添加按钮,按钮上添加文字和图片
  8. vs服务器连接xp系统,xp系统远程连接服务器
  9. 实现 SSH 无密码登录 、 ssh 常用命令
  10. 全国计算机二级c 笔记,[IT认证]全国计算机等级考试二级C语言笔记.doc
  11. 黑马程序员_Java学习日记num4
  12. IS-IS详解(二十)——IS-IS 多拓扑
  13. windows10 查看端口占用
  14. 微软windows10易升_Win10 如何摆脱易升这个流氓软件,如何拒绝每半年一次的大更...
  15. 使用Zoiper与freeSWITCH开视频会议
  16. linux系统终端快捷键,Linux终端快捷键整理
  17. iOS 字体pt和px的转换
  18. 吴恩达2022机器学习课程评测来了!
  19. 中职计算机c语言课程,中职计算机C语言教学探讨
  20. Unity Shader 皮肤水滴效果

热门文章

  1. 面向接口编程详解---编程实例
  2. 数据分析岗位面试必备
  3. 【numpy】数组增加一维(升维)小结
  4. PyTorch批训练及优化器比较
  5. 基于遥感影像实现三种方法提取枣树面积精度分析
  6. node解决request返回内容gzip乱码问题
  7. sublime test3 php语法错误高亮
  8. java使用httpClient解决外部url请求访问
  9. android通过手机热点通信
  10. Cannot run program /usr/local/android-sdk-linux/build-tools/23.0.2/aapt: error=2, No such file or