采用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

java中什么可以实现互斥锁_操作系统

 截图2:

java中什么可以实现互斥锁_操作系统_02

 

截图3:

java中什么可以实现互斥锁_操作系统_03

两个线程号分别以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。