• 多线程互斥问题


    采用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
    ", 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。

  • 相关阅读:
    web test Grinder / nGrinder / ngrinder / gor / tcpcopy
    【python学习】之五、可调用对象
    【C/C++学习】之五、dynamic_cast
    【网络编程】之一、初识WinSocket
    【啊哈!算法】之四、选择排序
    【IOS学习】之二、虚拟机MAC Lion 10.7 下问题集锦和xcode的安装
    【网络编程】之二、socket API学习
    【C/C++学习】之六、reinterpret_cast
    【啊哈!算法】之五、归并排序
    【IOS学习】之一、VM8下安装mac lion10.7 黑苹果之续
  • 原文地址:https://www.cnblogs.com/scu-cjx/p/7736876.html
Copyright © 2020-2023  润新知