C++,pthreads:如何从多个线程停止工作线程

C++, pthreads: how to stop a worker thread from multiple threads

本文关键字:线程 停止工作 pthreads C++      更新时间:2023-10-16

我需要能够阻止单个工作线程继续从任意其他线程中的任意点执行,包括但不限于主线程。我去年制作了我认为是工作的代码,但今天在一些线程死锁之后的调查表明它似乎无法正常工作,尤其是在互斥锁方面。

每次在主start_path_explorer线程中调用帮助程序方法 start_path_explorer() 时,代码都需要在工作线程中运行一次特定方法 path_explorer_t::step(

)。 另一个方法 stop_path_explorer() 必须能够随时由任何线程调用(运行 path_explorer_t::step()的线程除外),并且在确定 path_explorer_t::step() 完全完成之前不得返回。

此外,如果 karte_t::world->is_terminating_threads() 为 true,则不得调用 path_explorer_t::step(),而必须在下次有机会时终止线程。线程不得在其他情况下终止。

我为此编写的代码如下:

void* path_explorer_threaded(void* args) { karte_t* 世界 = (karte_t*)参数; path_explorer_t::allow_path_explorer_on_this_thread = 真; karte_t::p ath_explorer_step_progress = 2; 做 { simthread_barrier_wait(&start_path_explorer_barrier); karte_t::p ath_explorer_step_progress = 0; simthread_barrier_wait(&start_path_explorer_barrier); pthread_mutex_lock(&path_explorer_mutex); if (karte_t::world->is_terminating_threads()) { karte_t::p ath_explorer_step_progress = 2; pthread_mutex_unlock(&path_explorer_mutex); 破; } path_explorer_t::step(); karte_t::p ath_explorer_step_progress = 1; pthread_cond_signal(&path_explorer_conditional_end); karte_t::p ath_explorer_step_progress = 2; pthread_mutex_unlock(&path_explorer_mutex); } while (!karte_t::world->is_terminating_threads()); karte_t::p ath_explorer_step_progress = -1; pthread_exit(空); 返回参数; } 无效 karte_t::stop_path_explorer() { #ifdef MULTI_THREAD_PATH_EXPLORER pthread_mutex_lock(&path_explorer_mutex); 如果 (path_explorer_step_progress = 0) { pthread_cond_wait(&path_explorer_conditional_end,&path_explorer_mutex); } pthread_mutex_unlock(&path_explorer_mutex); #endif } 无效 karte_t::start_path_explorer() { #ifdef MULTI_THREAD_PATH_EXPLORER 如果 (path_explorer_step_progress == -1) { 线程路径资源管理器已终止,因此不要等待 否则我们将出现线程死锁。 返回; } pthread_mutex_lock(&path_explorer_mutex); 如果 (path_explorer_step_progress> 0) { simthread_barrier_wait(&start_path_explorer_barrier); } if(path_explorer_step_progress> -1) { simthread_barrier_wait(&start_path_explorer_barrier); } pthread_mutex_unlock(&path_explorer_mutex); #endif }

但是,我发现,由于我不理解的原因,stop_path_explorer() 中的互斥锁无法正常工作,并且它不会阻止互斥锁线在path_explorer_threaded中传递,结果是调用 stop_path_explorer() 的线程可能在cond_wait处等待,而工作线程本身可能在"do"下方的顶部屏障处等待。它似乎还能够产生互斥锁可以解锁两次的条件,这会导致未定义的行为,除非我将其设置为递归。

我只需要将互斥属性设置为递归并在 stop_path_explorer() 中的条件语句中添加额外的解锁,还是需要更基本的重新设计?如果是后者,有人对如何去做有任何建议吗?

提前感谢您的任何帮助。

在进一步调查之后,我认为我对自己的问题有一个潜在的答案。

我误解了 pthread_cond_wait() 如何与互斥锁结合使用 - 文档说它锁定,而不是解锁传递给它的互斥锁。

这意味着互斥锁从同一线程被双重锁定,这产生了未定义的行为,并且可能会导致我看到的一些奇怪的问题。

现在,我已使用第二个互斥锁重写了代码,如下所示(代码示例中未显示新定义):

void* path_explorer_threaded(void* args) { karte_t* 世界 = (karte_t*)参数; path_explorer_t::allow_path_explorer_on_this_thread = 真; karte_t::p ath_explorer_step_progress = 2; int mutex_error = 0; 做 { simthread_barrier_wait(&start_path_explorer_barrier); karte_t::p ath_explorer_step_progress = 0; simthread_barrier_wait(&start_path_explorer_barrier);   if (karte_t::world->is_terminating_threads()) { karte_t::p ath_explorer_step_progress = 2; 破; } path_explorer_t::step(); mutex_error = pthread_mutex_lock(&path_explorer_mutex); karte_t::p ath_explorer_step_progress = 1; mutex_error = pthread_mutex_unlock(&path_explorer_mutex); pthread_cond_signal(&path_explorer_conditional_end); mutex_error = pthread_mutex_lock(&path_explorer_mutex); karte_t::p ath_explorer_step_progress = 2; mutex_error = pthread_mutex_unlock(&path_explorer_mutex); } while (!karte_t::world->is_terminating_threads()); karte_t::p ath_explorer_step_progress = -1; pthread_exit(空); 返回参数; } 无效 karte_t::stop_path_explorer() { #ifdef MULTI_THREAD_PATH_EXPLORER int mutex_error = 0; 而 (path_explorer_step_progress == 0) { mutex_error = pthread_mutex_lock(&path_explorer_mutex); pthread_cond_wait(&path_explorer_conditional_end,&path_explorer_cond_mutex); 如果 (&path_explorer_mutex) { mutex_error = pthread_mutex_unlock(&path_explorer_mutex); mutex_error = pthread_mutex_unlock(&path_explorer_cond_mutex); } } #endif } 无效 karte_t::start_path_explorer() { #ifdef MULTI_THREAD_PATH_EXPLORER 如果 (path_explorer_step_progress == -1) { 线程路径资源管理器已终止,因此不要等待 否则我们将出现线程死锁。 返回; } 如果 (path_explorer_step_progress> 0) { simthread_barrier_wait(&start_path_explorer_barrier); } if(path_explorer_step_progress> -1) { simthread_barrier_wait(&start_path_explorer_barrier); } #endif }

但是,我不相信这段代码完全正常工作。从中获取该软件的软件,一个开源计算机游戏,旨在使用锁步网络在多玩家配置中通过互联网播放(这意味着服务器和客户端必须准确地从定义的起点准确执行代码,否则它们将不同步)。使用此代码时,客户端最终将与服务器不同步,而它们不会与原始代码不同步(前提是服务器和客户端运行相同的可执行文件:当可执行文件以不同的方式编译时,我遇到了客户端和服务器不同步的问题,例如 GCC 和 Visual Studio, 我怀疑未定义的行为可能是那里的罪魁祸首)。

如果有人可以确认我的新代码是否正确或有任何明显的缺陷,我将不胜感激。