如何在不成为竞争条件的情况下等待条件?
How do I wait on a condition without it being a race condition?
如果您 运行 按原样编写代码,您可能不会遇到任何问题。问题是如果广播发生在 cond_wait 之前,此代码将不再有效。如果您取消注释下面的睡眠,您将每隔 运行
遇到一次问题
我该如何写才不会出现竞争条件?我碰巧知道我可以使用 futex 解决这个问题,但我正在寻找 pthread 解决方案
//clang++ -g -fsanitize=undefined,thread main.cpp && ./a.out
#include <cstdio>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t checkpoint = PTHREAD_COND_INITIALIZER;
int data;
void*fn(void*) {
pthread_mutex_lock(&write_lock);
auto temp = ++data;
pthread_mutex_unlock(&write_lock);
//This if makes it so no thread will pass until both/all threads have finished writing to data
if (temp < 2) {
//sleep(1); // <--------- uncomment to see problem
while (temp < 2)
{
pthread_mutex_t local_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&local_mutex);
pthread_cond_wait(&checkpoint, &local_mutex);
//Recheck the condition
pthread_mutex_lock(&write_lock);
temp = data;
pthread_mutex_unlock(&write_lock);
}
} else {
pthread_cond_broadcast(&checkpoint);
}
int sum=data; //no way to get here until both/all threads execute the sync code
return 0;
}
int main() {
pthread_t thread_id[2];
for(int i=0; i<2; i++) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&thread_id[i], &attr, &fn, 0);
}
for(int i=0; i<2; i++) {
pthread_join(thread_id[i], 0);
}
printf("Finish\n");
}
可能我不清楚你真正的问题。这看起来像是您正在尝试堆叠您的客户端线程,直到 all 它们都超过了特定的检查点。在这种情况下,一旦 data
被所有线程
触发,就会实现该检查点
因此,data
保留您的谓词状态。测试或编写它是互斥锁保护的目的。 变化检测 是 cond-var 的目的。
#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t checkpoint = PTHREAD_COND_INITIALIZER;
int data;
void *fn(void *pv)
{
// construction-passed top limit
intptr_t n = (intptr_t)pv;
// changing predicate, so lock mutex
pthread_mutex_lock(&write_lock);
++data;
// changed predicate, so tell people.
pthread_cond_signal(&checkpoint);
// mutex is still locked. if our predicate state isn't
// sufficient to move on, we wait (and release the mutex
// in the process)
while (data < n)
{
pthread_cond_wait(&checkpoint, &write_lock);
// TODO: woke up here. may be spurious, may be legit, but
// we're going to make sure on the next iteration of the
// loop by rechecking the predicate data, which we can do
// because the mutex is locked coming out of the wait.
// ALSO: if you want off-the-mutex processing here of some
// kind you would do it by releasing the mutex, do your
// thread work, then reacquire the mutex again before the
// next iteration of the loop
}
// NOTE: still own the mutex.
// no way to get here until all threads execute the sync code
// note: not a legit use of pthread_self, use at your peril
printf("%p : %d\n", (void*)pthread_self(), data);
// leaving the party, release the mtx and tell someone.
pthread_mutex_unlock(&write_lock);
pthread_cond_signal(&checkpoint);
return 0;
}
#define N_THREADS 16
int main()
{
pthread_t thread_id[N_THREADS];
for (intptr_t i = 0; i < N_THREADS; i++)
pthread_create(&thread_id[i], NULL, &fn, (void*)(intptr_t)N_THREADS);
for (intptr_t i = 0; i < N_THREADS; i++)
pthread_join(thread_id[i], 0);
printf("Finish\n");
}
输出(仅示例)
0x7000019e9000 : 16
0x700001448000 : 16
0x700001342000 : 16
0x700001654000 : 16
0x7000016d7000 : 16
0x7000012bf000 : 16
0x70000175a000 : 16
0x7000013c5000 : 16
0x7000017dd000 : 16
0x70000123c000 : 16
0x700001860000 : 16
0x70000154e000 : 16
0x7000018e3000 : 16
0x7000014cb000 : 16
0x700001966000 : 16
0x7000015d1000 : 16
Finish
这就是您 at-least 想要完成的目标。
如果您 运行 按原样编写代码,您可能不会遇到任何问题。问题是如果广播发生在 cond_wait 之前,此代码将不再有效。如果您取消注释下面的睡眠,您将每隔 运行
遇到一次问题我该如何写才不会出现竞争条件?我碰巧知道我可以使用 futex 解决这个问题,但我正在寻找 pthread 解决方案
//clang++ -g -fsanitize=undefined,thread main.cpp && ./a.out
#include <cstdio>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t checkpoint = PTHREAD_COND_INITIALIZER;
int data;
void*fn(void*) {
pthread_mutex_lock(&write_lock);
auto temp = ++data;
pthread_mutex_unlock(&write_lock);
//This if makes it so no thread will pass until both/all threads have finished writing to data
if (temp < 2) {
//sleep(1); // <--------- uncomment to see problem
while (temp < 2)
{
pthread_mutex_t local_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&local_mutex);
pthread_cond_wait(&checkpoint, &local_mutex);
//Recheck the condition
pthread_mutex_lock(&write_lock);
temp = data;
pthread_mutex_unlock(&write_lock);
}
} else {
pthread_cond_broadcast(&checkpoint);
}
int sum=data; //no way to get here until both/all threads execute the sync code
return 0;
}
int main() {
pthread_t thread_id[2];
for(int i=0; i<2; i++) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&thread_id[i], &attr, &fn, 0);
}
for(int i=0; i<2; i++) {
pthread_join(thread_id[i], 0);
}
printf("Finish\n");
}
可能我不清楚你真正的问题。这看起来像是您正在尝试堆叠您的客户端线程,直到 all 它们都超过了特定的检查点。在这种情况下,一旦 data
被所有线程
因此,data
保留您的谓词状态。测试或编写它是互斥锁保护的目的。 变化检测 是 cond-var 的目的。
#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t checkpoint = PTHREAD_COND_INITIALIZER;
int data;
void *fn(void *pv)
{
// construction-passed top limit
intptr_t n = (intptr_t)pv;
// changing predicate, so lock mutex
pthread_mutex_lock(&write_lock);
++data;
// changed predicate, so tell people.
pthread_cond_signal(&checkpoint);
// mutex is still locked. if our predicate state isn't
// sufficient to move on, we wait (and release the mutex
// in the process)
while (data < n)
{
pthread_cond_wait(&checkpoint, &write_lock);
// TODO: woke up here. may be spurious, may be legit, but
// we're going to make sure on the next iteration of the
// loop by rechecking the predicate data, which we can do
// because the mutex is locked coming out of the wait.
// ALSO: if you want off-the-mutex processing here of some
// kind you would do it by releasing the mutex, do your
// thread work, then reacquire the mutex again before the
// next iteration of the loop
}
// NOTE: still own the mutex.
// no way to get here until all threads execute the sync code
// note: not a legit use of pthread_self, use at your peril
printf("%p : %d\n", (void*)pthread_self(), data);
// leaving the party, release the mtx and tell someone.
pthread_mutex_unlock(&write_lock);
pthread_cond_signal(&checkpoint);
return 0;
}
#define N_THREADS 16
int main()
{
pthread_t thread_id[N_THREADS];
for (intptr_t i = 0; i < N_THREADS; i++)
pthread_create(&thread_id[i], NULL, &fn, (void*)(intptr_t)N_THREADS);
for (intptr_t i = 0; i < N_THREADS; i++)
pthread_join(thread_id[i], 0);
printf("Finish\n");
}
输出(仅示例)
0x7000019e9000 : 16
0x700001448000 : 16
0x700001342000 : 16
0x700001654000 : 16
0x7000016d7000 : 16
0x7000012bf000 : 16
0x70000175a000 : 16
0x7000013c5000 : 16
0x7000017dd000 : 16
0x70000123c000 : 16
0x700001860000 : 16
0x70000154e000 : 16
0x7000018e3000 : 16
0x7000014cb000 : 16
0x700001966000 : 16
0x7000015d1000 : 16
Finish
这就是您 at-least 想要完成的目标。