UNIX环境高级编程——pthread_create的问题
linux 下常用的创建多线程函数pthread_create(pthread_t * thread , pthread_attr_t * attr , void *(*start_routine)(void*) , void *args);
其中第一个参数用来保存线程信息,第二个参数指新线程的运行属性,可以设置为NULL,第三个参数为自定义的线程函数,第四个参数就是线程函数需要用到的参数,一般如果要传递多个参数,可以设置为结构体(struct)类型,这里我们使用int类型的变量。
下面我着重讨论一个用for结构来创建多个线程时参数传递的问题:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> #define th_pop 20 pthread_mutex_t mutex; pthread_t a_thread[th_pop]; void * thread_func(void *args)
{
pthread_mutex_lock(&mutex);
int t_id = *(int*)args;
printf("the id of this thread is %d\n",t_id);
pthread_mutex_unlock(&mutex);
return (void*)NULL;
} void init()
{
pthread_mutex_init(&mutex, NULL);
int i;
for( i=0; i<th_pop; i++)
{
pthread_create(&a_thread[i] , NULL , thread_func , &i);
}
//wait the end of the threads;
for( i=0; i<th_pop; i++)
{
int res = pthread_join(a_thread[i] , NULL);
if(res != 0)
printf("the thread id: %d ends fail \n",i);
}
pthread_mutex_destroy(&mutex); } int main()
{
init();
return 0;
}
运行结果:
huangcheng@ubuntu:~$ ./a.out
the id of this thread is 2
the id of this thread is 8
the id of this thread is 9
the id of this thread is 9
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
看到这个结果有没有感觉到有什么不对呢?可能你会感觉到很纳闷,怎么出现了那么多的id=0的结果呢?其实这个认真分析一下并不难理解:
首先pthread_create函数传递的是一个指针型的参数,即传递的是一个地址而已,这样在执行for结构时:
for(int i=0; i<th_pop; i++)
{
pthread_create(&a_thread[i] , NULL , thread_func , &i);
}
该for循环快速执行完成,并且将i置为20,故而传递的地址指向的内容为20,同时其它的线程还没来得及执行: int t_id = *(int*)args;
这样就使得多个线程都指向同一个地址,内容为20,解决该问题的一个办法为中for结构中加入sleep(1),这样当sleep时间大于线程函数执行时间,就可以得到一个正确的结果,不过这种办法剥掉了并发性,并不可取,下面我们采用另一种方法。
我们只修改init()函数
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> #define th_pop 20 // pthread_mutex_t mutex; pthread_t a_thread[th_pop]; void * thread_func(void *args)
{
pthread_mutex_lock(&mutex);
int t_id = *(int*)args;
printf("the id of this thread is %d\n",t_id);
pthread_mutex_unlock(&mutex);
return (void*)NULL;
} void init()
{
pthread_mutex_init(&mutex, NULL);
int thread_id[th_pop];
int i;
for( i=0; i<th_pop; i++)
thread_id[i] = i;
for( i=0; i<th_pop; i++)
{
int *t = thread_id +i;
pthread_create(&a_thread[i] , NULL , thread_func , (void*)t);
}
//wait the end of the threads;
for( i=0; i<th_pop; i++)
{
int res = pthread_join(a_thread[i] , NULL);
if(res != 0)
printf("the thread id: %d ends fail \n",i);
}
pthread_mutex_destroy(&mutex); } int main()
{
init();
return 0;
}
运行结果:
huangcheng@ubuntu:~$ ./a.out
the id of this thread is 3
the id of this thread is 2
the id of this thread is 1
the id of this thread is 4
the id of this thread is 5
the id of this thread is 6
the id of this thread is 7
the id of this thread is 8
the id of this thread is 9
the id of this thread is 10
the id of this thread is 11
the id of this thread is 12
the id of this thread is 13
the id of this thread is 14
the id of this thread is 15
the id of this thread is 16
the id of this thread is 17
the id of this thread is 18
the id of this thread is 19
the id of this thread is 0
从这个例子中我们应该明白,要避免直接在传递的参数中传递发生改变的量,否则会导致结果不可测。
解决这类问题的办法:
(1)复制一份到堆里面。
(2)加锁。(一般做法)
(3)用结构体数组。(推荐这个)
(4)sleep。(不推荐)
UNIX环境高级编程——pthread_create的问题的更多相关文章
- (九) 一起学 Unix 环境高级编程 (APUE) 之 线程
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (十) 一起学 Unix 环境高级编程 (APUE) 之 线程控制
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- UNIX环境高级编程——线程属性
pthread_attr_t 的缺省属性值 属性 值 结果 scope PTHREAD_SCOPE_PROCESS 新线程与进程中的其他线程发生竞争. detachstate PTHREAD_CREA ...
- 【UNIX环境高级编程】线程同步
当多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图.如果每个线程使用的变量都是其他线程不会读取和修改的,那么就不存在一致性问题.同样,如果变量是只读的也不会有一致性问题.但是,当一个线程可 ...
- (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- multiple definition of `err_sys' 《UNIX环境高级编程》
本文地址:http://www.cnblogs.com/yhLinux/p/4079930.html 问题描述: [点击此处直接看解决方案] 在练习<UNIX环境高级编程>APUE程序清单 ...
- unix环境高级编程基础知识之第二篇(3)
看了unix环境高级编程第三章,把代码也都自己敲了一遍,另主要讲解了一些IO函数,read/write/fseek/fcntl:这里主要是c函数,比较容易,看多了就熟悉了.对fcntl函数讲解比较到位 ...
- (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
随机推荐
- SpringMVC与Zookeeper、Dubbo使用示例
Dubbo整合Zookeeper和spring示例程序 1.Dubbo架构 本篇文章基于dubbox,使用dubbo应该也可以正常运行. 我认为想讲清楚一个任何一个技术框架,首先熟悉架构是非常有必要的 ...
- 通过AIDL在两个APP之间Service通信
一.项目介绍 [知识准备] ①Android Interface definition language(aidl,android接口定义语言),其目的实现跨进程的调用.进程是程序在os中执行的载体, ...
- ftp传二进制文件时一定要用二进制模式,否则内容会有变化,造成后处理莫名其妙的错误,还以为传输前后内容一致,其实已变化。
ftp传二进制文件时一定要用二进制模式,否则内容会有变化,造成后处理莫名其妙的错误,还以为传输前后内容一致,其实已变化.
- ACM 饭卡
Problem Description 电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额.如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负) ...
- Docker 联合文件系统
联合文件系统(UnionFS)是一种分层.轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several dir ...
- Docker创建 tomcat/weblogic 集群
安装 tomcat 镜像 准备好需要的 jdk.tomcat 等软件放到 home 目录下面,启动一个容器 docker run -t -i -v /home:/opt/data --name mk_ ...
- Azure AI 服务之语音识别
笔者在前文<Azure AI 服务之文本翻译>中简单介绍了 Azure 认知服务中的文本翻译 API,通过这些简单的 REST API 调用就可以轻松地进行机器翻译.如果能在程序中简单的集 ...
- 炫酷:一句代码实现标题栏、导航栏滑动隐藏。ByeBurger库的使用和实现
本文已授权微信公众号:鸿洋(hongyangAndroid)原创首发. 其实上周五的时候已经发过一篇文章.基本实现了底部导航栏隐藏的效果.但是使用起来可能不是很实用.因为之前我实现的方式是继承了系统的 ...
- TCP发送源码学习(3)--tcp_transmit_skb
一.tcp_transmit_skb static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, g ...
- hive分区partition(动态和静态分区混合使用; partition的简介)
分区是hive存放数据的一种方式.将列值作为目录来存放数据,就是一个分区.这样where中给出列值时,只需根据列值直接扫描对应目录下的数据,不扫面其他不关心的分区,快速定位,查询节省大量时间.分动态和 ...