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多线程程序设计

线程理论基础:和进程相比,它是一种非常节俭的多任务操作方式。在Linux系统下,启动一个新的进程必须分配...
  • fuyuehua22
  • fuyuehua22
  • 2014年04月26日 13:20
  • 654

Linux程序设计学习笔记----多线程编程基础概念与基本操作

转载请注明出处,谢谢.
  • hu1020935219
  • hu1020935219
  • 2014年08月14日 14:22
  • 1894

Linux多线程程序设计

原文地址:http://blog.csdn.net/u011012049/article/details/47419331 线程:线程可以理解为“轻量级”的进程,它与创建它的进程共享代码段和数据段...
  • zhang2531
  • zhang2531
  • 2016年08月01日 20:12
  • 431

Win32多线程程序设计

Win32多线程程序设计”多线程多任务“是程序开发者和用户都需要的一个重要资产。从WindowsNT开始,完全支持32位程序的抢占式多任务。带领我们进入了”多线程多任务“时代。基本概念 进程(pro...
  • chenjintaoxp
  • chenjintaoxp
  • 2015年07月31日 16:04
  • 1208

Linux下基于socket和多线程的聊天室小程序

要求:基于TCP编写,一个聊天室最多100人。 客户端:   1、用户需要登录,登录时只需要输入一个昵称即可无需判断昵称是否重复(如果其他功能都ok考虑)   2、用户登录后连接服务器端,进入聊...
  • Robot__Man
  • Robot__Man
  • 2016年09月07日 16:23
  • 3448

Linux并发服务器编程之多线程并发服务器

上一篇文章使用fork函数实现了多进程并发服务器,但是也提到了一些问题: fork是昂贵的。fork时需要复制父进程的所有资源,包括内存映象、描述字等; 目前的实现使用了一种写时拷贝(copy-on-...
  • qq_29227939
  • qq_29227939
  • 2016年12月21日 11:21
  • 1439

多线程程序设计的8个规则

最近在学习互联网方面相关的内容,找到一篇关于多线程设计原则的,我觉得挺好的,跟大家一块分享出来; 规则一:找到真正不相关的计算任务   如果你将要执行的运算任务相互之间不独立的话,你是不可能将它们...
  • tang_huan_11
  • tang_huan_11
  • 2015年10月29日 14:04
  • 1365

windows程序设计:多任务与多线程

主线程处理用户输入(和其他消息),并创建进程中的其他进程,这些附加的线程完成与用户无关的任务。 一个程序中的线程是同一进程的不同部分,因此它们共享进程的资源(内存、打开的文件等),共享静态变量...
  • liyun123gx
  • liyun123gx
  • 2014年02月12日 17:47
  • 684

Linux程序设计-读书笔记1

chap 1 1.链接库分为静态链接库.a和共享库.so。 2.静态链接库示例: hello.c ---------------------------------------- #incl...
  • conanswp
  • conanswp
  • 2015年09月01日 22:04
  • 806

深入浅出Win32多线程程序设计

引言   从单进程单线程到多进程多线程是操作系统发展的一种必然趋势,当年的DOS系统属于单任务操作系统,最优秀的程序员也只能通过驻留内存的方式实现所谓的"多任务",而如今的Win32操作系统却可...
  • Qsir
  • Qsir
  • 2017年05月17日 15:09
  • 221
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux程序设计——多线程(第十二章)
举报原因:
原因补充:

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