使用全局变量时多线程编程的奇怪问题

时间:2018-01-24 04:09:08

标签: c linux multithreading global-variables

有点奇怪。我的情景如下:

在文件A.c中定义两个全局变量:

volatile bool g_test = true;
pthread_mutex_t g_test_mutex = PTHREAD_MUTEX_INITIALIZER;

在文件A.c中,全局变量是只读的。

...
pthread_mutex_lock(& g_test_mutex); 
if(! g_test){
     ret = -1;
     pthread_mutex_unlock(& g_test_mutex);
     goto cleanup;
 }
pthread_mutex_unlock(& g_test_mutex);
...

并将全局变量写入另一个文件B.c

...
extern volatile bool g_test;
extern pthread_mutex_t g_test_mutex;

bool tmpval = func_to_getval();

if(tmpval != g_test){
   pthread_mutex_lock(& g_test_mutex);
   g_test = tmpval;
   pthread_mutex_unlock(&g_test_mutex);
}
printf("g_test value:%s\n",g_test?"yes":"no");
...

以上代码都可以。

但删除最后一个printf语句时很奇怪,当g_test发生更改且文件A.c无法获取更新值时,无法成功同步该值。为什么?

更新

我更改了代码:

bool tmpval = func_to_getval();

if(tmpval != g_test){
   pthread_mutex_lock(& g_test_mutex);
   g_test = tmpval;
   pthread_mutex_unlock(&g_test_mutex);
}
printf("g_test value:%s\n",g_test?"yes":"no");

pthread_mutex_lock(&g_can_encrypted_mutex);
g_can_decrypted = func_to_getval(env); 
pthread_mutex_unlock(&g_can_encrypted_mutex);

它通过了。但是每次都会锁定互斥锁,使用这种方法会增加多少费用?

2 个答案:

答案 0 :(得分:1)

B.c不应该在没有持有g_test_mutex的情况下引用g_test;两个线程可以争夺这个代码,因为你在if中读取了g_test,然后在以后更新它,另一个线程可能会在此期间进入并更新g_test。

这意味着这个原始代码是错误的:

from tkinter import*

import tkinter.messagebox

root = Tk()

def func(label):
      tkinter.messagebox.askquestion("Information", "you have selected: ", label )


mymenu = Menu(root)
root.config(menu = mymenu)

submenu = Menu(mymenu)

mymenu.add_cascade(label = "file", menu = submenu)
submenu.add_command(label ="project", command = func)
submenu.add_command(label = "save", command = func)
submenu.add_separator()
submenu.add_command(label ="exit", command = func)

root.mainloop()

您应该在保存锁定时分配的局部变量中保留g_test的副本;然后在释放锁之后,在printf()中使用该局部。

当并发程序通过改变通信区域之外的时间来改变行为时,请寻找竞争条件。

答案 1 :(得分:0)

您的计划在printf通话后很快就会结束吗?您在main的末尾附近显示为B.c的代码,或者exit之后调用printf或类似的代码?如果是这样,那么您的程序可能会在A.c中的代码运行之前终止,并且对printf的调用只会延迟退出足够长的时间以使其有时间运行。如果是这种情况,您需要添加一些退出同步 - 例如,调用pthread_join