window 多進(jìn)程通信:共享內(nèi)存和事件

進(jìn)程通信

window 上跨進(jìn)程通信主要有幾種:共享內(nèi)存、管道、事件、Socket、郵件槽等。

在了解學(xué)習(xí)了window的IPC機(jī)制,需要實(shí)現(xiàn)

  • 發(fā)送端與接收端跨進(jìn)程通信;

  • 接收端可能處于正在運(yùn)行或者未運(yùn)行的狀態(tài),并且接收端可能上一次處于運(yùn)行狀態(tài),這一次就可能終止運(yùn)行了。

發(fā)送端:發(fā)送消息的一端,并且可能在接收端未啟動(dòng)時(shí)候,需要啟動(dòng)接收端;
接收端:負(fù)責(zé)接收信息的一端,隨時(shí)可能關(guān)閉運(yùn)行。


最后

  • 選擇 共享內(nèi)存機(jī)制 來(lái)傳遞消息的具體內(nèi)容;

  • 結(jié)合使用 事件 機(jī)制 ,事件的一個(gè)方法 WaitForSingleObject 負(fù)責(zé)阻塞等待事件消息,既可以保證跨進(jìn)程消息的即時(shí)性,同時(shí)也不需要用死循環(huán)來(lái)不斷的查看共享內(nèi)存是否有新的內(nèi)容寫(xiě)入,減少了CPU的負(fù)載。

  • 如果不熟悉window共享內(nèi)存,可以了解下: Windows 共享內(nèi)存映射文件
    以及事件:Windows API 創(chuàng)建事件

發(fā)送端的流程:

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

void Sender::start()
{
    std::cout<<"發(fā)送端"<<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())//判斷接收端是否運(yùn)行, 可以通過(guò)判斷eventhandler是否存在或者接收端進(jìn)程是否運(yùn)行
            {
                eventHandler = OpenEvent(EVENT_ALL_ACCESS, FALSE,  EventName);//獲取事件句柄
                SetEvent(eventHandler);//發(fā)送事件
            }
            else
            {
                startupReceiver();//啟動(dòng)接收端
            }
        }
    }
    //關(guān)閉
    UnmapViewOfFile(charBuffer);
    CloseHandle(fileMapHandler);
    CloseHandle(eventHandler);
}

接收端的流程:

void Receiver::start()
{
    std::cout<<"接收端"<<std::endl;
    while(1)
    {
        if (eventHandler != NULL)
        {
            ResetEvent(eventHandler);//重置為無(wú)信號(hào)狀態(tài)
        }

        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 << "收到內(nèi)容:"<<charBuffer << endl;
                memset(charBuffer, 0, strlen(charBuffer));
            }
        }
        if (eventHandler == NULL)
        {
            eventHandler = CreateEvent(NULL, FALSE, FALSE, LPCWSTR(EventName));
        }
        WaitForSingleObject(eventHandler, INFINITE);
    }
    //關(guān)閉
    UnmapViewOfFile(charBuffer);
    CloseHandle(fileMapHandler);
    CloseHandle(eventHandler);
}

以上

  1. 發(fā)送端負(fù)責(zé)創(chuàng)建共享內(nèi)存句柄,接收端負(fù)責(zé)創(chuàng)建事件句柄。

  2. 發(fā)送端先寫(xiě)入共享內(nèi)存,啟動(dòng)客戶(hù)端后會(huì)默認(rèn)先讀取共享內(nèi)存,再進(jìn)入事件等待;這樣能解決:在發(fā)送端首次想告訴客戶(hù)端消息,可是客戶(hù)端還未啟動(dòng)、發(fā)送端也還沒(méi)拿到事件句柄的時(shí)候,在接收端第一次啟動(dòng)之后,接收端馬上拿取共享內(nèi)存的內(nèi)容,實(shí)現(xiàn)了第一次的消息通信,以后后續(xù)的消息通過(guò)事件告知接收端,接收端再?gòu)墓蚕韮?nèi)存打開(kāi)獲取具體消息內(nèi)容。

  3. 每次發(fā)送端都重新獲取一次句柄是因?yàn)榻邮斩丝赡茈S時(shí)斷開(kāi),生成新的一次句柄,解決了接收端狀態(tài)不穩(wěn)定的問(wèn)題。

一點(diǎn)想法

個(gè)人對(duì)window IPC機(jī)制不熟悉,不過(guò)相信可能有更好的處理方式,例如郵件槽,邊學(xué)習(xí)邊努力吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容