window 多進程通信:共享內存和事件

進程通信

window 上跨進程通信主要有幾種:共享內存、管道、事件、Socket、郵件槽等。

在瞭解學習了window的IPC機制,需要實現

  • 發送端與接收端跨進程通信;

  • 接收端可能處於正在運行或者未運行的狀態,並且接收端可能上一次處於運行狀態,這一次就可能終止運行了。

發送端:發送消息的一端,並且可能在接收端未啓動時候,需要啓動接收端;
接收端:負責接收信息的一端,隨時可能關閉運行。


最後

  • 選擇 共享內存機制 來傳遞消息的具體內容;

  • 結合使用 事件 機制 ,事件的一個方法 WaitForSingleObject 負責阻塞等待事件消息,既可以保證跨進程消息的即時性,同時也不需要用死循環來不斷的查看共享內存是否有新的內容寫入,減少了CPU的負載。

  • 如果不熟悉window共享內存,可以瞭解下: Windows 共享內存映射文件
    以及事件:Windows API 創建事件

發送端的流程:

#define BUF_SIZE 1025  
const char EventName [] = "EventName";
const char FileMapName [] = "MapFile";  

void Sender::start()
{
    std::cout<<"發送端"<<std::endl;
    fileMapHandler =  CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUF_SIZE, MapFileName);
    charBuffer = (char *)MapViewOfFile( fileMapHandler, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);

    std::string input;
    while(1)
    {
        getline(std::cin, input);
        if (!input.empty())
        {
            strncpy(charBuffer, input.c_str(), BUF_SIZE - 1);
            charBuffer[BUF_SIZE - 1] = '\0';

            if (isReceiverWork())//判斷接收端是否運行, 可以通過判斷eventhandler是否存在或者接收端進程是否運行
            {
                eventHandler = OpenEvent(EVENT_ALL_ACCESS, FALSE,  EventName);//獲取事件句柄
                SetEvent(eventHandler);//發送事件
            }
            else
            {
                startupReceiver();//啓動接收端
            }
        }
    }
    //關閉
    UnmapViewOfFile(charBuffer);
    CloseHandle(fileMapHandler);
    CloseHandle(eventHandler);
}

接收端的流程:

void Receiver::start()
{
    std::cout<<"接收端"<<std::endl;
    while(1)
    {
        if (eventHandler != NULL)
        {
            ResetEvent(eventHandler);//重置爲無信號狀態
        }

        fileMapHandler = OpenFileMapping(FILE_MAP_ALL_ACCESS, TRUE, LPCWCHAR(MapFileName));
        charBuffer = (char *)MapViewOfFile(fileMapHandler, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);  
        
        if (fileMapHandler != NULL)
        {
            if (charBuffer != NULL)
            {
                cout << "收到內容:"<<charBuffer << endl;
                memset(charBuffer, 0, strlen(charBuffer));
            }
        }
        if (eventHandler == NULL)
        {
            eventHandler = CreateEvent(NULL, FALSE, FALSE, LPCWSTR(EventName));
        }
        WaitForSingleObject(eventHandler, INFINITE);
    }
    //關閉
    UnmapViewOfFile(charBuffer);
    CloseHandle(fileMapHandler);
    CloseHandle(eventHandler);
}

以上

  1. 發送端負責創建共享內存句柄,接收端負責創建事件句柄。

  2. 發送端先寫入共享內存,啓動客戶端後會默認先讀取共享內存,再進入事件等待;這樣能解決:在發送端首次想告訴客戶端消息,可是客戶端還未啓動、發送端也還沒拿到事件句柄的時候,在接收端第一次啓動之後,接收端馬上拿取共享內存的內容,實現了第一次的消息通信,以後後續的消息通過事件告知接收端,接收端再從共享內存打開獲取具體消息內容。

  3. 每次發送端都重新獲取一次句柄是因爲接收端可能隨時斷開,生成新的一次句柄,解決了接收端狀態不穩定的問題。

一點想法

個人對window IPC機制不熟悉,不過相信可能有更好的處理方式,例如郵件槽,邊學習邊努力吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章