奇怪的 pthread_mutex_t 行为

weird pthread_mutex_t behavior

考虑下一段代码 -

#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;
}

我简单地创建了三个 pthreads 并赋予它们相同的函数 foo,希望每个线程轮流打印并递减 sharedIndex

但这是输出 -

10
9
8
7
6
5
4
3
2
1
0
-1
-2

编辑

此外,似乎只有第一个线程递减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

我希望所有线程都会减少共享源 - 意思是,每次上下文切换,不同的线程都会访问资源并执行它的操作。

线程将在 pthread_mutex_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;
}

根据此代码,sharedIndex 是所有线程的共享资源

因此,对它的每次访问(读和写)都应该由互斥体包装。 否则假设所有线程同时采样 sharedIndex 且其值为 1.

的情况

然后,所有线程进入 while 循环,每个线程都将 sharedIndex 减 1,最后到达 -2

编辑

可能的修复(作为可能的选项之一):

bool is_positive;
do
{
    pthread_mutex_lock(&mutex);

    is_positive = (sharedIndex >= 0);
    if (is_positive)
    {
        cout << sharedIndex << endl;
        sharedIndex--;
    }

    pthread_mutex_unlock(&mutex);
}while(is_positive);

EDIT2

注意必须初始化互斥量:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

此程序的行为未定义。

您还没有初始化互斥量。您需要调用 pthread_mutex_init 或静态初始化它:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

你在临界区之外读取了这个变量:

while(sharedIndex >= 0)

这意味着您可以在另一个线程更新垃圾值时读取它。在锁定互斥量并对其进行独占访问之前,不应读取共享变量。

编辑:

it seems that only the first thread decrements the sharedIndex

那是因为未定义的行为。解决上述问题,您应该会看到其他线程 运行.

使用您当前的代码,允许编译器假定 sharedIndex 从未被其他线程更新,因此它不会费心重新读取它,而只是让第一个线程 运行十次,然后其他两个线程运行各一次。

Meaning, every contex switch, a different thread will access the resource and do its thing.

不能保证 pthread 互斥锁的行为是公平的。如果你想保证每个线程轮流 运行 的循环行为,那么你需要自己强加它,例如通过另一个共享变量(可能还有一个条件变量)来说明轮到哪个线程 运行,并阻塞其他线程直到轮到它们。