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;
}
- 我不明白为什么当
达到0李>sharedIndex
受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)