简体   繁体   English

奇怪的pthread_mutex_t行为

[英]weird pthread_mutex_t behavior

Consider the next piece of code - 考虑下一段代码-

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

I simply created three pthreads and gave them all the same function foo , in hope that every thread, at its turn, will print and decrement the sharedIndex . 我简单地创建了三个pthreads并将所有相同的函数foo赋予它们,希望每个线程依次输出并减少sharedIndex

But this is the output - 但这是输出-

10
9
8
7
6
5
4
3
2
1
0
-1
-2
  • I don't understand why the process doesn't stop when sharedIndex reaches 0. 我不明白为什么sharedIndex达到0时进程不会停止。
  • sharedIndex is protected by a mutex . sharedIndexmutex量保护。 How come it's accessed after it became 0? 它变成0后如何访问? Aren't the threads supposed to directly skip to return NULL; 线程不是应该直接跳过以return NULL; ?

EDIT 编辑

In addition, it seems that only the first thread decrements the sharedIndex . 另外,似乎只有第一个线程才会减少sharedIndex Why isn't every thread decrement the shared resource at it's turn? 为什么不是每个线程都递减共享资源? Here's the output after a fix - 这是修复后的输出-

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

I wish that all of the thread will decrement the shared source - Meaning, every contex switch, a different thread will access the resource and do its thing. 我希望所有线程都会减少共享源-意思是,每个contex开关,一个不同的线程都将访问该资源并执行其操作。

This program's behaviour is undefined. 该程序的行为是不确定的。

You have not initialized the mutex. 您尚未初始化互斥锁。 You need to either call pthread_mutex_init or statically initialize it: 您需要调用pthread_mutex_init或将其静态初始化:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

You read this variable outside the critical section: 您在关键部分之外阅读了此变量:

while(sharedIndex >= 0)

That means you could read a garbage value while another thread is updating it. 这意味着您可以在另一个线程对其进行更新时读取垃圾值。 You should not read the shared variable until you have locked the mutex and have exclusive access to it. 在锁定互斥锁并对其具有独占访问权限之前,您不应阅读共享变量。

Edit: 编辑:

it seems that only the first thread decrements the sharedIndex 似乎只有第一个线程会减少sharedIndex

That's because of the undefined behaviour. 那是因为行为不确定。 Fix the problems above and you should see other threads run. 解决以上问题,您应该看到其他线程正在运行。

With your current code the compiler is allowed to assume that the sharedIndex is never updated by other threads, so it doesn't bother re-reading it, but just lets the first thread run ten times, then the other two threads run once each. 使用您当前的代码,编译器可以假定sharedIndex不会被其他线程更新,因此它不会费心重新读取它,而只是让第一个线程运行十次,然后让其他两个线程各运行一次。

Meaning, every contex switch, a different thread will access the resource and do its thing. 这意味着,每个contex开关,一个不同的线程都将访问该资源并执行其操作。

There is no guarantee that pthread mutexes behave fairly. 无法保证pthread互斥体的行为公平。 If you want to guarantee a round-robin behaviour where each thread runs in turn then you will need to impose that yourself, eg by having another shared variable (and maybe a condition variable) that says which thread's turn it is to run, and blocking the other threads until it is their turn. 如果要保证每个线程轮流运行的循环行为,则需要自己强加它,例如,通过使用另一个共享变量(可能是条件变量)来说明要运行哪个线程,并阻塞其他线程,直到轮到他们了。

The threads will be hanging out on pthread_mutex_lock(&mutex); 线程将挂在pthread_mutex_lock(&mutex); waiting to get the lock. 等待获得锁。 Once a thread decrements to 0 and releases the lock, the next thread waiting at lock will then go about it's business (making the value -1), and same for the next thread (making the value -2). 一旦线程递减为0并释放了锁,下一个等待锁的线程将开始处理该事务(使值变为-1),对下一个线程(使值变为-2)也将继续处理。

You need to alter your logic on checking value and locking the mutex. 您需要更改检查值和锁定互斥锁的逻辑。

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

According to this code sharedIndex is the shared resource for all the threads. 根据此代码, sharedIndex是所有线程的共享资源

Thus each access to it (both read and write) should be wrapped by mutex. 因此,对它的每次访问(读和写)都应由互斥体包装。 Otherwise assume the situation where all the threads sample sharedIndex simultaneously and its value is 1 . 否则,假设所有线程同时采样sharedIndex且其值为1

All threads, then, enter the while loop and each one decreases sharedIndex by one leading it to -2 at the end. 然后,所有线程都进入while循环,每个线程都将sharedIndexsharedIndex ,最后将其导致-2

EDIT 编辑

Possible fix (as one of the possible options): 可能的修复(作为可能的选项之一):

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 编辑2

Note that you must initialize the mutex: 请注意,您必须初始化互斥锁:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM