c - 设置共享变量时应该使用临界区还是内存屏障?

标签 c multithreading winapi

假设我有以下代码:

/* Global Variables */

int flag = 0;
int number1;
int number2;

//------------------------------------

/* Thread A */

number1 = 12345;
number2 = 678910;
flag = 1;

//------------------------------------

/* Thread B */

while (flag == 0) {}
printf("%d", number1);
printf("%d", number2);

线程A中,代码可能不是按顺序执行的,可能会像这样执行:

/* Thread A */

flag = 1;
number1 = 12345;
number2 = 678910;

为了防止这种情况,我应该使用内存屏障。

但我不确定是否应该使用常规内存屏障,例如:

/* Thread A */

number1 = 12345;
number2 = 678910;
MEMORY_BARRIER_GOES_HERE
flag = 1;

或者如果我应该使用关键部分,例如:

/* Thread A */

number1 = 12345;
number2 = 678910;
EnterCriticalSection(&cs);
flag = 1;
LeaveCriticalSection(&cs);

最佳答案

尝试巧妙地使用无锁线程模型(屏障、原子、互锁操作等)来保护多个变量而不是标准锁定机制只会导致错误。

您需要用锁(关键部分)保护所有变量(number1number2flag)

线程A:

EnterCriticalSection(&cs);
    flag = 1;
    number1 = 12345;
    number2 = 678910;
LeaveCriticalSection(&cs);

线程B:

while (1)
{
    int n1, n2;

    EnterCriticalSection(&cs);
    if (flag)
    {
        n1 = number1;
        n2 = number2;
        break;
    }
    LeaveCriticalSection(&cs);
}
printf("%d", n1);
printf("%d", n2);

此外,在 Windows 上,您可以使用 Conditional Variable 避免整个 while (flag == 0) {} 循环烧毁 CPU 内核。 。从连续轮询机制切换到基于通知的机制将比尝试执行棘手的互锁操作产生更好的性能结果。

更好:

线程A:

EnterCriticalSection(&cs);
    flag = 1;
    number1 = 12345;
    number2 = 678910;
LeaveCriticalSection(&cs);
WakeAllConditionVariable(&conditional_variable);

线程B:

EnterCriticalSection(&cs);

while (flag == 0)
{
    // This will atomically Leave the CS and block until the conditional_variable is fired by the other thread

    SleepConditionVariableCS(&conditional_variable, &cs, INFINITE);

    // After it returns, it will re-enter the CS.
}

n1 = number1;
n2 = number2;
LeaveCriticalSection(&cs);
printf("%d", n1);
printf("%d", n2);   

关于c - 设置共享变量时应该使用临界区还是内存屏障?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50431955/

相关文章:

Java:持有锁时创建新线程是常见的做法吗?

c++ - CRecordset::snapshot 在 VS2012 中不再起作用——有什么选择?

winapi - 赢API : Hook every window show or process execution

c++ - MFC/CCriticalSection : Simple lock situation hangs

c - 冗余或良好实践 - 结构

c++ - 为什么我的 scanf() 没有在数组上迭代 for 循环?

c - 为什么C要在<math.h>中定义M_2_SQRTPI常量?

c# - 连接池与max_connection的关系

c++ - C++:如果没有来自串行端口的新数据,如何忽略ReadFile()?

c++ - 如何将字符串(字符数组)中的 UUID 转换为静态 uint8_t adv_data[31]