簡體   English   中英

C ++:Linux平台上的線程同步方案

[英]C++: Thread synchronization scenario on Linux Platform

我正在為Linux平台實現多線程C ++程序,我需要一個類似於WaitForMultipleObjects()的功能。

在搜索解決方案時,我觀察到有些文章描述了如何在Linux中使用示例實現WaitForMultipleObjects()功能,但這些示例不滿足我必須支持的場景。

我的情況非常簡單。 我有一個守護進程,主線程將一個方法/回調暴露給外部世界,例如暴露給DLL。 DLL的代碼不在我的控制之下。 相同的主線程創建一個新線程“線程1”。 線程1必須執行一種無限循環,在該循環中它將等待關閉事件(守護程序關閉)或它將等待通過上面提到的公開方法/回調發出信號的數據可用事件。

簡而言之,線程將等待關閉事件和數據可用事件,其中如果發出關閉事件,則等待將滿足並且循環將被破壞或者如果數據可用事件被發信號通知則等待將滿足並且線程將進行業務處理。

在Windows中,它似乎非常直接。 下面是我的場景的基於MS Windows的偽代碼。

//**Main thread**

//Load the DLL
LoadLibrary("some DLL")

//Create a new thread
hThread1 = __beginthreadex(..., &ThreadProc, ...)

//callback in main thread (mentioned in above description) which would be called by the     DLL
void Callbackfunc(data)
{
    qdata.push(data);
    SetEvent(s_hDataAvailableEvent);
}

void OnShutdown()
{
    SetEvent(g_hShutdownEvent);
    WaitforSingleObject(hThread1,..., INFINITE);
    //Cleanup here
}

//**Thread 1**

unsigned int WINAPI ThreadProc(void *pObject)
{
    while (true)
    {

        HANDLE hEvents[2];
        hEvents[0] = g_hShutdownEvent;
        hEvents[1] = s_hDataAvailableEvent;

        //3rd parameter is set to FALSE that means the wait should satisfy if state of  any one of the objects is signaled.
        dwEvent = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
        switch (dwEvent) 
        {   
            case WAIT_OBJECT_0 + 0: 
            // Shutdown event is set, break the loop
            return 0;   

            case WAIT_OBJECT_0 + 1:
            //do business processing here
            break; 

            default: 
            // error handling
        }
    }
}

我想為Linux實現相同的功能。 根據我對Linux的理解,它有完全不同的機制,我們需要注冊信號。 如果終止信號到達,則進程將知道它即將關閉但在此之前,進程必須等待正在運行的線程正常關閉。

在Linux中執行此操作的正確方法是使用條件變量。 雖然這與Windows中的WaitForMultipleObjects ,但您將獲得相同的功能。

使用兩個bool來確定是否有可用數據或必須關閉。 然后讓關閉功能和數據功能都相應地設置bool,並發出條件變量的信號。

#include <pthread.h>

pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_t hThread1; // this isn't a good name for it in linux, you'd be 
                    // better with something line "tid1" but for 
                    // comparison's sake, I've kept this

bool shutdown_signalled;
bool data_available;

void OnShutdown()
{
    //...shutdown behavior...
    pthread_mutex_lock(&mutex);
    shutdown_signalled = true;
    pthread_mutex_unlock(&mutex);
    pthread_cond_signal(&cv);
}

void Callbackfunc(...)
{
    // ... whatever needs to be done ...
    pthread_mutex_lock(&mutex);
    data_available = true;
    pthread_mutex_unlock(&mutex);
    pthread_cond_signal(&cv);
}


void *ThreadProc(void *args)
{
    while(true){
        pthread_mutex_lock(&mutex);
        while (!(shutdown_signalled || data_available)){
            // wait as long as there is no data available and a shutdown
            // has not beeen signalled
            pthread_cond_wait(&cv, &mutex);
        }
        if (data_available){
            //process data
            data_available = false;
        }
        if (shutdown_signalled){
            //do the shutdown
            pthread_mutex_unlock(&mutex);
            return NULL;
        }
        pthread_mutex_unlock(&mutex); //you might be able to put the unlock
        // before the ifs, idk the particulars of your code
    }
}
int main(void)
{
    shutdown_signalled = false;
    data_available = false;
    pthread_create(&hThread1, &ThreadProc, ...);
    pthread_join(hThread1, NULL);
    //...
}

我知道windows也有條件變量,所以這看起來不應該太陌生。 我不知道windows對它們有什么規則,但是在POSIX平台上, wait需要在while循環中,因為“虛假的喚醒”可能會發生。

如果您希望編寫unix或linux特定代碼,則可以使用不同的API:

  • pthread:提供線程,互斥,條件變量
  • IPC(進程間通信)機制:互斥,信號量,共享內存
  • 信號

對於線程,第一個庫是必需的(Linux上有較低級別的系統調用,但它更繁瑣)。 對於事件,可以使用三者。

系統關閉事件生成終止(SIG_TERM)和終止所有相關進程的kill(SIG_KILL)信號。 因此,也可以通過這種方式啟動單個守護程序關閉。 游戲的目標是捕獲信號,並啟動進程關閉。 重點是:

  • 信號機制是以不必等待它們的方式制作的

    只需使用sigaction安裝一個所謂的處理程序,系統將完成剩下的工作。

  • 信號被設置為進程, 任何線程都可以攔截它(處理程序可以在任何上下文中執行)

    因此,您需要安裝信號處理程序(請參閱sigaction(2) ),並以某種方式將信息傳遞給應用程序必須終止的其他線程。

最方便的方法可能是擁有一個全局互斥鎖保護標志,所有線程都會定期查詢。 信號處理程序將設置該標志以指示關閉。 對於工作線程,它意味着

  • 告訴遠程主機服務器正在關閉,
  • 在讀取時關閉其套接字
  • 處理所有剩余的接收命令/數據並發送答案
  • 關閉插座
  • 出口

對於主線程,這將意味着在工作線程上啟動連接,然后退出。

此模型不應干擾數據正常處理的方式:如果捕獲到信號,則對selectpoll的阻塞調用將返回錯誤EINTR ,對於非阻塞調用,線程正在定期檢查該標志,因此它確實有效太。

暫無
暫無

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

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