簡體   English   中英

C ++,pthreads:如何從多個線程停止工作線程

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

我需要能夠阻止單個工作線程繼續從任意其他線程(包括但不限於主線程)中的任意點繼續執行。 去年,我編寫了我認為可以正常工作的代碼,但是在進行了一些線程死鎖之后,今天的調查表明,它似乎無法正常工作,尤其是在互斥鎖方面。

每次在主線程中調用輔助方法start_path_explorer()時,代碼都需要在工作線程中恰好運行一次特定方法path_explorer_t :: step()。 僅從主線程調用start_path_explorer()。

另一個方法stop_path_explorer()必須能夠在任何時間(除了運行path_explorer_t :: step()的線程之外)隨時被任何線程調用,並且除非確定path_explorer_t :: step()已完全釋放,否則它不得返回。完成。

此外,如果karte_t :: world-> is_terminate_threads()為true,則不得調用path_explorer_t :: step(),而必須在下一個機會終止線程。 該線程不得在其他情況下終止。

我為此編寫的代碼如下:

void* path_explorer_threaded(void* args)
    {
        karte_t* world = (karte_t*)args;
        path_explorer_t::allow_path_explorer_on_this_thread = true;
        karte_t::path_explorer_step_progress = 2;

        do
        {
            simthread_barrier_wait(&start_path_explorer_barrier);
            karte_t::path_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::path_explorer_step_progress = 2;
                pthread_mutex_unlock(&path_explorer_mutex);
                break;
            }

            path_explorer_t::step();

            karte_t::path_explorer_step_progress = 1;

            pthread_cond_signal(&path_explorer_conditional_end);
            karte_t::path_explorer_step_progress = 2;
            pthread_mutex_unlock(&path_explorer_mutex);
        } while (!karte_t::world->is_terminating_threads());

        karte_t::path_explorer_step_progress = -1;
        pthread_exit(NULL);
        return args;
    }


    void karte_t::stop_path_explorer()
    {
    #ifdef MULTI_THREAD_PATH_EXPLORER
        pthread_mutex_lock(&path_explorer_mutex);

        if (path_explorer_step_progress = 0)
        {
            pthread_cond_wait(&path_explorer_conditional_end, &path_explorer_mutex);
        }

        pthread_mutex_unlock(&path_explorer_mutex);
    #endif
    }

    void karte_t::start_path_explorer()
    {
    #ifdef MULTI_THREAD_PATH_EXPLORER
        if (path_explorer_step_progress == -1)
        {
            // The threaded path explorer has been terminated, so do not wait
            // or else we will get a thread deadlock.
            return;
        }
        pthread_mutex_lock(&path_explorer_mutex);
        if (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* world = (karte_t*)args;
        path_explorer_t::allow_path_explorer_on_this_thread = true;
        karte_t::path_explorer_step_progress = 2;
        int mutex_error = 0;

        do
        {
            simthread_barrier_wait(&start_path_explorer_barrier);
            karte_t::path_explorer_step_progress = 0;
            simthread_barrier_wait(&start_path_explorer_barrier);   

            if (karte_t::world->is_terminating_threads())
            {
                karte_t::path_explorer_step_progress = 2;
                break;
            }

            path_explorer_t::step();

            mutex_error = pthread_mutex_lock(&path_explorer_mutex);
            karte_t::path_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::path_explorer_step_progress = 2;
            mutex_error = pthread_mutex_unlock(&path_explorer_mutex);

        } while (!karte_t::world->is_terminating_threads());

        karte_t::path_explorer_step_progress = -1;
        pthread_exit(NULL);
        return args;
    }


    void karte_t::stop_path_explorer()
    {
    #ifdef MULTI_THREAD_PATH_EXPLORER
        int mutex_error = 0;

        while (path_explorer_step_progress == 0)
        {
            mutex_error = pthread_mutex_lock(&path_explorer_mutex);
            pthread_cond_wait(&path_explorer_conditional_end, &path_explorer_cond_mutex);
            if (&path_explorer_mutex)
            {
                mutex_error = pthread_mutex_unlock(&path_explorer_mutex);
                mutex_error = pthread_mutex_unlock(&path_explorer_cond_mutex);
            }
        }

    #endif
    }

    void karte_t::start_path_explorer()
    {
    #ifdef MULTI_THREAD_PATH_EXPLORER
        if (path_explorer_step_progress == -1)
        {
            // The threaded path explorer has been terminated, so do not wait
            // or else we will get a thread deadlock.
            return;
        }
        if (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 
    }

但是,我認為此代碼無法完全正常工作。 以此為基礎的軟件(一種開放源代碼的計算機游戲)被設計為可以使用鎖步網絡在Internet上以多玩家配置在互聯網上播放(這意味着服務器和客戶端必須從定義的起點完全確定地執行代碼,或者他們將不同步)。 使用此代碼時,客戶端最終將與服務器不同步,而客戶端將與原始代碼不同步(前提是服務器和客戶端運行的是相同的可執行文件:客戶端和服務器退出時遇到麻煩當可執行文件的編譯方式不同時(例如,GCC和Visual Studio,並且我懷疑未定義的行為可能是造成這種情況的罪魁禍首)。

如果有人可以確認我的新代碼是正確的還是存在任何明顯的缺陷,我將不勝感激。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM