如何加入首先完成的线程?
How to join with whichever thread finishes first?
主线程生成 > 1 个线程,每个线程都可以调用 return 并返回一个错误值。如果出现这种情况,其他线程继续没有意义,应该取消。
所以,我希望我的主线程:
- 加入最先完成的线程;
- 检查此线程是否 returned 错误,如果是,则取消所有其他线程。
但是,pthread_join
要求我指定要加入的线程。例如,如果我调用 pthread_join(thread1, thread1_ret)
,并且 thread2
以错误完成,那么我将无法知道 thread2
在 thread1
完成之前因错误完成,并且thread2
过早完成的事实很可能意味着 thread1
当前正在等待一个永远不会发出信号的条件变量,因为只有 thread2
可能会发出该变量的信号……所以,不好。
如果 thread2
完成,我希望我的主线程取消 thread1
,反之亦然。
如何实现?
How to accomplish this?
您需要一个单独的沟通渠道。
一个典型的解决方案涉及一个队列(已完成的线程)和一个条件变量。
以错误结束的线程将自己放入队列并在返回前发出条件信号。主线程等待条件,检查队列,并加入它在那里找到的线程,然后取消所有其他线程。
另请注意,异步线程取消很难做到正确。通常最好有一个所有线程定期检查的全局变量:while (!exit_requested) { do_work(); }
你想要这样的东西:
struct thread_data {
int stop;
pthread_cond_t * flag;
pthread_mutex_t * lock;
int * failCount;
int * successCount;
};
void * foobar(void * ptr)
{
struct thread_data * data = (struct thread_data*)ptr;
int fail = 0;
while (isWorkToBeDone() && !data->stop) {
// do some work
if (encounteredError()) {
pthread_mutex_lock(data->lock);
data->failCount += 1;
fail = 1;
pthread_cond_signal(data->flag);
pthread_mutex_unlock(data->lock);
}
}
// clean up
if (!fail) {
pthread_mutex_lock(data->lock);
data->successCount += 1;
pthread_cond_signal(data->flag);
pthread_mutex_unlock(data->lock);
}
pthread_exit(NULL);
}
int runThreads()
{
pthread_t * threads;
pthread_mutex_t lock;
pthread_cond_t flag;
int i;
struct thread_data data;
threads = malloc(sizeof(*threads)*numThreads);
if (!threads) {
// handle malloc error
return 0;
}
// initialize mutex and condition variable
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&flag, NULL);
data.stop = 0;
data.flag = &flag;
data.lock = &lock;
data.failCount = 0;
data.successCount = 0;
for (i = 0; i < numThreads; ++i) {
if (!pthread_create(threads+i, NULL, foobar,
(void *)(threads+i))) {
// handle thread creation error
}
}
while (!data.stop) {
pthread_mutex_lock(&lock);
pthread_cond_wait(&cond, &lock);
// a thread just finished
if (data.failCount > 0) {
data.stop = 1;
} else if (data.successCount == numThreads) {
data.stop = 1;
}
pthread_mutex_unlock(&lock);
}
for (i = 0; i < numThreads; ++i) {
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&flag);
free(threads);
}
它的工作方式是等待一个线程失败或所有线程成功,然后让所有线程知道停止工作并通过 stop
变量干净退出。
您可以调用 pthread_kill()
,而不是让线程检查 stop
变量,但最好完全退出每个线程。
主线程生成 > 1 个线程,每个线程都可以调用 return 并返回一个错误值。如果出现这种情况,其他线程继续没有意义,应该取消。
所以,我希望我的主线程:
- 加入最先完成的线程;
- 检查此线程是否 returned 错误,如果是,则取消所有其他线程。
但是,pthread_join
要求我指定要加入的线程。例如,如果我调用 pthread_join(thread1, thread1_ret)
,并且 thread2
以错误完成,那么我将无法知道 thread2
在 thread1
完成之前因错误完成,并且thread2
过早完成的事实很可能意味着 thread1
当前正在等待一个永远不会发出信号的条件变量,因为只有 thread2
可能会发出该变量的信号……所以,不好。
如果 thread2
完成,我希望我的主线程取消 thread1
,反之亦然。
如何实现?
How to accomplish this?
您需要一个单独的沟通渠道。
一个典型的解决方案涉及一个队列(已完成的线程)和一个条件变量。
以错误结束的线程将自己放入队列并在返回前发出条件信号。主线程等待条件,检查队列,并加入它在那里找到的线程,然后取消所有其他线程。
另请注意,异步线程取消很难做到正确。通常最好有一个所有线程定期检查的全局变量:while (!exit_requested) { do_work(); }
你想要这样的东西:
struct thread_data {
int stop;
pthread_cond_t * flag;
pthread_mutex_t * lock;
int * failCount;
int * successCount;
};
void * foobar(void * ptr)
{
struct thread_data * data = (struct thread_data*)ptr;
int fail = 0;
while (isWorkToBeDone() && !data->stop) {
// do some work
if (encounteredError()) {
pthread_mutex_lock(data->lock);
data->failCount += 1;
fail = 1;
pthread_cond_signal(data->flag);
pthread_mutex_unlock(data->lock);
}
}
// clean up
if (!fail) {
pthread_mutex_lock(data->lock);
data->successCount += 1;
pthread_cond_signal(data->flag);
pthread_mutex_unlock(data->lock);
}
pthread_exit(NULL);
}
int runThreads()
{
pthread_t * threads;
pthread_mutex_t lock;
pthread_cond_t flag;
int i;
struct thread_data data;
threads = malloc(sizeof(*threads)*numThreads);
if (!threads) {
// handle malloc error
return 0;
}
// initialize mutex and condition variable
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&flag, NULL);
data.stop = 0;
data.flag = &flag;
data.lock = &lock;
data.failCount = 0;
data.successCount = 0;
for (i = 0; i < numThreads; ++i) {
if (!pthread_create(threads+i, NULL, foobar,
(void *)(threads+i))) {
// handle thread creation error
}
}
while (!data.stop) {
pthread_mutex_lock(&lock);
pthread_cond_wait(&cond, &lock);
// a thread just finished
if (data.failCount > 0) {
data.stop = 1;
} else if (data.successCount == numThreads) {
data.stop = 1;
}
pthread_mutex_unlock(&lock);
}
for (i = 0; i < numThreads; ++i) {
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&flag);
free(threads);
}
它的工作方式是等待一个线程失败或所有线程成功,然后让所有线程知道停止工作并通过 stop
变量干净退出。
您可以调用 pthread_kill()
,而不是让线程检查 stop
变量,但最好完全退出每个线程。