linux程序设计——多线程(第十二章)

原创 2015年07月07日 20:05:59

12.8    多线程

之前,总是让程序的主线程仅仅创建一个线程,这节将演示如何在同一个程序中创建多个线程,然后如何以不同于其启动顺序将它们合并在一起。此外,还演示多线程编程时容易出现的时序问题.
编写程序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 6

void *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程序设计》多线程学习

thread8.c在同一个程序中创建多个线程#include #include #include #include #define NUM_THREADS 6void *thread_funct...

【原创】《Linux高级程序设计》杨宗德著 - Linux多线程编程 - 多线程异步管理 - 信号

【原创】《Linux高级程序设计》杨宗德著 - Linux多线程编程 - 多线程异步管理 - 信号

.NET组件程序设计 第8章 多线程和并发管理

^-^ 终于到多线程了!嘿咻。。。嘿咻。。。 线程和多线程:线程仅仅是一个进程中一条执行路径。通常在应用程序提供上下文中执行。.NET中线程为基本执行单元。.NET线程是操作系统底层线程托管代码表示。...

.NET组件程序设计 第8章 多线程和并发管理 同步线程_可等待事件

3.可等待事件(EventWaitHandle)EventWaitHandle派生自WaitHandle,用于跨线程通知事件。EventWaitHandle有两种方式:手动重置(ManualReset...

关于线程和多线程,JAVA高并发程序设计

关于线程和多线程,面试里你所要知道的一切(一)主要整理一些关于线程的知识,尽量做到言简意赅,面试的时候用。线程前段时间找工作,很多次问到关于线程的问题,回答的时候就开启背书模式:线程是轻量级的进程,是...

谈单进程(单线程)与单进程(多线程)程序设计

本文单进程指单进程(单线程)模式;单线程也指单进程单线程;多线程指单进程(多线程模式),下同。   最近在B部门做项目,用到的平台框架都是基于单进程模式的,在以前的A部门做过的项目都是多线程模式的...

windows程序设计(第2版 王艳平)学习记要:3.1 多线程

CreateProcess函数创建了线程,每个进程至少有一个主线程,这个线程从入口地址main开始执行,直到return语句返回,主线程结束,进程从内存中卸载。 主线程可在运行过程中创建新的线程...

《多核程序设计》PART 6:OpenMP 一种可移植的多线程解决方案(转载)

OpenMP中的任务循环调度和分块对于内存利用比较好的情况下,对于负载平衡可能是不利的;同样,有利于负载平衡的策略也有可能对访存的性能不利。因此,在对性能优化时,必须在优化内存利用和优化负载平衡之间进...

.NET简谈组件程序设计之(多线程与并发管理一)

由于多线程的内容比较多我会用几篇文章来讲解。 多线程在我们日常开发过程中用的很多,上一篇“.NET简谈组件程序设计之(异步委托)”详细的讲解了基于委托的多线程使用,委托是基于后台线程池的原理,这篇文...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)