奇怪的 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
时不停止
达到 0。
sharedIndex
受 mutex
保护。变成0后怎么访问了?线程不是应该直接跳到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
我希望所有线程都会减少共享源 - 意思是,每次上下文切换,不同的线程都会访问资源并执行它的操作。
线程将在 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 互斥锁的行为是公平的。如果你想保证每个线程轮流 运行 的循环行为,那么你需要自己强加它,例如通过另一个共享变量(可能还有一个条件变量)来说明轮到哪个线程 运行,并阻塞其他线程直到轮到它们。
考虑下一段代码 -
#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。 sharedIndex
受mutex
保护。变成0后怎么访问了?线程不是应该直接跳到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
我希望所有线程都会减少共享源 - 意思是,每次上下文切换,不同的线程都会访问资源并执行它的操作。
线程将在 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 互斥锁的行为是公平的。如果你想保证每个线程轮流 运行 的循环行为,那么你需要自己强加它,例如通过另一个共享变量(可能还有一个条件变量)来说明轮到哪个线程 运行,并阻塞其他线程直到轮到它们。