奇怪的pthread_mutex_t行为

时间:2016-04-21 16:05:15

标签: 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 << 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时这个过程不会停止 达到0.
  • sharedIndexmutex保护。如何在它变为0后访问它? Aren的线程应该直接跳到return 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

我希望所有的线程都会减少共享源 - 意思是,每个上下文切换,一个不同的线程将访问资源并做其事。

3 个答案:

答案 0 :(得分:4)

此程序的行为未定义。

您尚未初始化互斥锁。您需要致电pthread_mutex_init或静态初始化它:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

您在关键部分之外阅读此变量:

while(sharedIndex >= 0)

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

修改

  

似乎只有第一个线程会减少sharedIndex

那是因为未定义的行为。修复上面的问题,你应该看到其他线程运行。

使用当前代码,编译器可以假设sharedIndex永远不会被其他线程更新,因此它不会重新读取它,只是让第一个线程运行十次,然后其他两个线程各运行一次。

  

意思是,每个上下文切换,一个不同的线程将访问资源并做其事情。

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

答案 1 :(得分:3)

线程将挂在pthread_mutex_lock(&mutex);等待获取锁定。一旦一个线程递减到0并释放锁定,那么等待锁定的下一个线程将继续它的业务(使值为-1),并且对于下一个线程(使值-2)相同。 / p>

您需要在检查值和锁定互斥锁时更改逻辑。

答案 2 :(得分:3)

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减少一个,最后将-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);

修改

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

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

<强> EDIT2

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

<BASE>