繁体   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