簡體   English   中英

創建在進程之間共享的全局命名計數器

[英]Creating global named counter shared between processes

如何在c ++中創建可以在多個進程之間共享的全局計數器值? 我需要的是一種使多個進程立即“無效”的方法,以信號通知它們執行某些操作(例如從文件讀取)。 所有進程都將連續輪詢(每10ms)以獲取當前計數器值,並將其與內部存儲的最后一個值進行比較。 值不匹配將表明需要做一些工作。

編輯:順便說一句,我的進程正在執行為不同的.exe:s,而不是從某些父進程創建的。 操作系統是Windows。

命名信號量呢? Posix支持它,不確定Windows。

考慮一下您要分配信息的方式和潛在的重疊-如果任何讀者完成閱讀所花的時間比刷新所花費的時間長,那么您將在建議的方法中遇到麻煩。

我閱讀問題的方式有很多讀者,作者不知道(或在大多數情況下)一次有多少讀者,但想通知讀者有新內容可供閱讀。

如果不知道有多少潛在的讀者,就無法使用簡單的互斥或信號量來了解何時完成閱讀器,不知道每個人何時完成,就無法掌握何時重置事件以通知下一個事件的好信息。讀取事件。

MS Windows特定:

共享的細分
一種選擇是將變量放置在共享數據段中。 這意味着,具有相同段的所有exe都可以讀取(或寫入)相同的變量,或者將其放入DLL中-加載共享的DLL。

有關更多信息,請參見http://www.codeproject.com/KB/DLL/data_seg_share.aspx

// Note: Be very wary of using anything other than primitive types here!
#pragma data_seg(".mysegmentname") 
HWND hWnd = NULL; 
LONG nVersion = -1;
#pragma data_seg()
#pragma comment(linker, "/section:.mysegmentname,rws")

IPC-COM
使您的主應用成為com服務,工作人員可以在其中注冊事件,然后將更改推送到每個事件接收器。

IPC-雙重事件
假設任何一個讀周期都比寫事件之間的時間短得多。 創建2個手動重置事件,在任何時候最多會發信號通知其中一個事件,並在事件之間交替。 信令將立即釋放所有閱讀器,完成閱讀后,他們將等待替代事件。

您可以使用簡便的方法,也可以使用簡便的方法將共享值存儲在注冊表或文件中,以便所有進程都同意經常檢查它。

困難的方法是使用IPC(進程間通信,我最常用的方法是NamedPipes。它不太難,因為您可以在網上找到很多有關IPC的資源。

如果使用* nix,則可以使進程從命名管道 (或套接字)中讀取,然后在其中寫入特定的msg,以告知其他進程應關閉它們。

IPC性能:命名管道與套接字

Windows NAmed Pipes在Linux中的替代方案

使用具有手動重置功能的命名事件對象。 以下解決方案使用CPU不如忙等待

發送過程:

  • 設定事件
  • 睡眠10毫秒
  • 重設活動

接收流程:

  • 設置事件后,所有等待的過程都會通過
  • 他們讀了文件
  • 讓他們睡眠20毫秒,因此說兩次無法看到同一事件。
  • 再等一下

Sleep(10)實際上可能比Sleep(20)花費更長的時間,但這只會導致另一個周期(再次讀取未更改的文件)。

由於可執行文件的名稱是已知的,所以幾天前我在一個項目中用C#實現了另一個解決方案:每個讀取器進程都創建一個命名事件“ Global \\ someuniquestring_%u”,其中%u是它的進程ID。 。 如果發出事件信號,則讀取文件並進行工作。 發送者進程具有事件句柄列表,如果文件已更改,則將它們設置為活動狀態,從而通知所有讀取器進程。 有時,例如,當文件已更改時,它必須更新事件句柄列表:

  • 獲取名稱為“ reader.exe”的所有進程(例如)
  • 為每個進程獲取它的ID
  • 如果它是一個新進程,請為現有事件“ Global \\ someuniquestring_%u”打開一個句柄。
  • 關閉不再處理的所有句柄。

找到了一種監視文件夾更改(使用“ event_trigger” -event)並從文件讀取其他事件信息的解決方案:

HANDLE event_trigger;
__int64 event_last_time;
vector<string> event_info_args;
string event_info_file = "event_info.ini";

// On init
event_trigger = FindFirstChangeNotification(".", false, FILE_NOTIFY_CHANGE_LAST_WRITE);
event_last_time = stat_mtime_force("event_info.ini");

// On tick
if (WaitForSingleObject(event_trigger, 0)==0)
{
    ResetEventTrigger(event_trigger);

    if (stat_mtime_changed("event_info.ini", event_last_time))
    {
        FILE* file = fopen_force("event_info.ini");

        char buf[4096];
        assert(fgets(buf, sizeof(buf), file));
        split(buf, event_info_args, "\t\r\n");
        fclose(file);

        // Process event_info_args here...

        HWND wnd = ...;
        InvalidateRect(wnd,0,false);
    }
}

// On event invokation
FILE* file = fopen("event_info.ini", "wt");
assert(file);
fprintf(file,"%s\t%s\t%d\n",
    "par1", "par2", 1234);
fclose(file);

stat_mtime_changed("event_info.ini", event_last_time);


// Helper functions:
void ResetEventTrigger()
{
    do
    {
        FindNextChangeNotification(evt);
    }
    while(WaitForSingleObject(evt, 0)==0);
}
FILE* fopen_force(const char* file);
{
    FILE* f = fopen(file, "rt");
    while(!f)
    {
        Sleep(10+(rand()%100));
        f = fopen(f, "rt");
    }
    assert(f);
    return f;
}
__int64 stat_mtime_force(const char* file)
{
    struct stat stats;
    int res = stat(file, &stats);
    if(res!=0)
    {
        FILE* f = fopen(file, "wt");
        fclose(f);
        res = stat(file, &stats);
    }
    assert(res==0);
    return stats.st_mtime;
}
bool stat_mtime_changed(const char* file, __int64& time);
{
    __int64 newTime = stat_mtime(file);
    if (newTime - time > 0)
    {
        time = newTime;
        return true;
    }
    return false;
}

暫無
暫無

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

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