多线程互斥问题
采用pthread_create建立一个新线程,与fork方式建立新进程不同(尽管在Linux环境下进程与线程具有相同概念)。所有pthread将会共用主线程中的所有变量,而不是如fork方式仅仅将所有变量引用加1。由于pthread共用问题的存在,将会引发在Linux下多线程编程的互斥问题。测试如下:
代码示例:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pthread.h> 4 5 int counter = 0; 6 //pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER; 7 8 void *doit(void *arg); 9 10 int main(void) 11 { 12 pthread_t tida, tidb; 13 14 pthread_create(&tida, NULL, &doit, NULL); 15 pthread_create(&tidb, NULL, &doit, NULL); 16 17 pthread_join(tida, NULL); 18 pthread_join(tidb, NULL); 19 20 exit(0); 21 } 22 23 void *doit(void *arg) 24 { 25 int i, val; 26 27 for(i = 0;i < 100; i++) { 28 //pthread_mutex_lock(&counter_mutex); 29 30 val = counter; 31 printf("%d : %d\n", pthread_self(), val + 1); 32 counter = val + 1; 33 34 //pthread_mutex_unlock(&counter_mutex); 35 } 36 37 return NULL; 38 }
a与b线程执行doit函数,并将循环100次将共用变量counter加1。
输入结果如下:
截图1
截图2:
截图3:
两个线程号分别以20,24进行标识,我们把C编译器进行加运算符转换为3条机器指令,第一条是从内存中取数据装载到寄存器,第二条是递减寄存器,第三条是从寄存器取数据存储到内存。从截图可以看出执行结果为:
截图1中,20号线程首先运行,执行打印代码并执行counter = val + 1,当其运行到counter = 10(counter=9+1)时,被CPU剥夺执行权限,此时交由24号线程运行(20号线程等待运行printf代码),24号线程首次执行val = counter,i=0,并将当前val值赋值为10,CPU剥夺其执行权限,20号线程重新运行(24号线程等待运行printf代码),20号线程继续执行printf,打印输出结果一直到打印到19,CPU剥夺执行权限交由24号线程,24号线程执行printf,打印输出结果11(val+1)
截图2中,24号线程一直运行,直到结束都没有被CPU切出,但其初始值val从10开始,故最后一次打印结果为110,24号线程执行结束,返回。20号线程被CPU唤醒,执行printf,打印输出20
截图3中,20号线程一直运行,直到结束,返回。
从执行结果也可以看出,由于未加互斥操作,使得24号线程初始运行时,counter为10,而且在24号线程结束运行counter被置为109时,位于20号线程中counter没有及时被同步,使得20号线程继续从19开始递增。
为避免上述问题存在,添加互斥锁方式可以进行解决,将上述代码注释位置去掉。通过添加互斥锁的方式,线程在操作counter变量前锁住该互斥锁,如果试图对一个已经上锁的互斥锁上锁,则该线程将会被阻塞,知道互斥锁被解锁。最终输出结果,计数器将会单调递增,最终值为200。
posted on 2017-10-26 15:03 chenjx_ucs 阅读(326) 评论(0) 编辑 收藏 举报