zoukankan      html  css  js  c++  java
  • linux程序设计——多线程(第十二章)

    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 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...
    ");
    	/* 主线程中等待合并这些子线程,但并非以创建它们的顺序来合并 */
    	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
    ");
    		} else {
    			perror("pthread_join failed");
    		}
    	}
    	printf("All done
    ");
    	exit(EXIT_SUCCESS);
    }
    
    void *thread_function(void *arg) {
    	int my_number = *(int *)arg;
    	int rand_num;
    	
    	printf("thread_function is running. Argument was %d
    ", my_number);
    	/* 创建的线程等待一段随机的时间退出执行 */
    	rand_num = 1 + (int)(9.0 * rand() / (RAND_MAX + 1.0));
    	sleep(rand_num);
    	printf("Bye from %d
    ", 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
    ", my_number);
        rand_num = 1 + (int)(9.0 * rand() / RAND_MAX + 1.0));
        sleep(rand_num);
        printf("Bye from %d
    ", 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;

  • 相关阅读:
    iOS 新建xib文件时,最外层view的约束问题
    React native 无法弹出调试控件的问题
    从GitHub下载demo时遇到的依赖问题
    Mac 解决 Sourcetree 同步代码总需要密码的问题
    Mac 安装JRE 1.8
    正则表达式-- (.*?) 或 (.*+)
    字符串内有多个#号,每俩#号为一组,JavaScript 截取每组#号之间的字符
    Js/jQuery实时监听input输入框值变化
    Redis设置密码
    redis本机能访问 远程不能访问的问题
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/7101314.html
Copyright © 2011-2022 走看看