C++ 奇怪的pthread\u mutex\t行为

C++ 奇怪的pthread\u mutex\t行为,c++,multithreading,pthreads,C++,Multithreading,Pthreads,考虑下一段代码- #include <iostream> using namespace std; int sharedIndex = 10; pthread_mutex_t mutex; void* foo(void* arg) { while(sharedIndex >= 0) { pthread_mutex_lock(&mutex); cout << sharedIndex << en

考虑下一段代码-

#include <iostream>

using namespace std;

int sharedIndex = 10;
pthread_mutex_t mutex;

void* foo(void* arg)
{
    while(sharedIndex >= 0)
    {
        pthread_mutex_lock(&mutex);

        cout << sharedIndex << endl;
        sharedIndex--;

        pthread_mutex_unlock(&mutex);
    }

    return NULL;
}

int main() {

    pthread_t p1;
    pthread_t p2;
    pthread_t p3;

    pthread_create(&p1, NULL, foo, NULL);
    pthread_create(&p2, NULL, foo, NULL);
    pthread_create(&p3, NULL, foo, NULL);

    pthread_join(p1, NULL);
    pthread_join(p2, NULL);
    pthread_join(p3, NULL);

    return 0;
}
  • 我不明白为什么当
    sharedIndex
    达到0
  • sharedIndex
    互斥锁的保护。它变成0后怎么会被访问?线程不应该直接跳到
    返回NULL
编辑

此外,似乎只有第一个线程递减
sharedIndex
。 为什么不是每个线程都在轮到它的时候减少共享资源? 这是修复后的输出-

Current thread: 140594495477504
10
Current thread: 140594495477504
9
Current thread: 140594495477504
8
Current thread: 140594495477504
7
Current thread: 140594495477504
6
Current thread: 140594495477504
5
Current thread: 140594495477504
4
Current thread: 140594495477504
3
Current thread: 140594495477504
2
Current thread: 140594495477504
1
Current thread: 140594495477504
0
Current thread: 140594495477504
Current thread: 140594478692096
Current thread: 140594487084800

我希望所有的线程都会减少共享源代码,也就是说,每个contex开关,一个不同的线程都会访问资源并完成它的工作。

线程将挂在
pthread\u mutex\u lock(&mutex)上等待获取锁。一旦一个线程递减到0并释放锁,在锁处等待的下一个线程将继续它的工作(使值为-1),下一个线程也是如此(使值为-2)

您需要更改检查值和锁定互斥锁的逻辑

int sharedIndex = 10;
pthread_mutex_t mutex;

void* foo(void* arg)
{
    while(sharedIndex >= 0)
    {
        pthread_mutex_lock(&mutex);

        cout << sharedIndex << endl;
        sharedIndex--;

        pthread_mutex_unlock(&mutex);
    }

    return NULL;
}
EDIT2

请注意,必须初始化互斥锁:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

此程序的行为未定义

您尚未初始化互斥锁。您需要调用
pthread\u mutex\u init
或静态初始化它:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
您在临界部分之外读取此变量:

while(sharedIndex >= 0)
这意味着您可以在另一个线程更新垃圾值时读取垃圾值。在锁定互斥锁并以独占方式访问互斥锁之前,不应读取共享变量

编辑:

似乎只有第一个线程递减
sharedIndex

那是因为未定义的行为。修复上面的问题,您将看到其他线程正在运行

对于您当前的代码,编译器可以假设其他线程从未更新过
sharedIndex
,因此它不需要重新读取它,只需让第一个线程运行十次,然后其他两个线程各运行一次

也就是说,每一个contex切换,都会有一个不同的线程访问资源并执行其操作


不能保证pthread互斥体的行为是公平的。如果您想保证每个线程轮流运行的循环行为,那么您需要自己强制执行,例如,通过使用另一个共享变量(可能还有一个条件变量)来说明轮到哪个线程运行,在创建线程之前,请尝试调用
pthread\u mutex\u init
,在程序的最后,请尝试修复代码中未定义的行为,看看它是否有帮助。我确实更改了代码,它成功了。但是,仍然只有一个线程减少了resource@AlexGoft这是最有效的行为。切换线程需要时间,因此实现尝试让每个线程至少运行几毫秒。谢谢,David。你的意思是在切换第一个线程和第二个线程之间,第一个线程会多次锁定和解锁互斥锁,从而导致资源减少到0?这是一个很好的答案,直到最后一段获得了否决票
volatile
在这里不起作用,编译器永远不会将变量的访问移到互斥锁之外(除非编译器完全被破坏),所以它是否使用寄存器无关紧要,只要结果在关键部分的末尾出现在内存中。@JonathanWakely编译器可能(可能)将函数开头的
sharedIndex
移动到
eax
,并将其存储回
sharedIndex
返回之前的位置。也许它不会这样做,但我不知道是否有任何“法律”可以应用在这里,这将阻止编译器这样做。如果编译器知道
pthread\u mutex\u lock
pthread\u mutex\u unlock
的实现,则可能会得出结论:没有任何东西会影响
sharedIndex
sharedIndex
不会影响这些函数。因此,这样的优化是可能的。如果编译器知道
pthread\u mutex\u lock
pthread\u mutex\u unlock
的实现,那么它就会知道它们包含必要的内存同步,以防止您担心的事情发生,所以不会出错。如果它不知道实现,那么它无论如何也不能这样做,所以它仍然不会出错。在这里使用
volatile
是没有用的,会引起混乱<代码> Value对于C和C++中的多线程编程无效。编译器可以为OP的代码使用寄存器,并且永远不会重新读取共享变量,因为它具有未定义的行为。但是如果它固定停止读取关键部分之外的变量,那么它就不能这样做。请进行投票,这现在是一个非常好的答案:)上有相关链接,但该站点暂时不可用
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
while(sharedIndex >= 0)