创建进程间共享的全局命名计数器

时间:2010-11-23 19:31:08

标签: c++ ipc counter

如何创建可在c ++中的多个进程之间共享的全局计数器值?我需要的是一种“一次”使多个进程“无效”的方法,指示它们执行某些操作(比如从文件读取)。所有进程将连续轮询(每10ms)获取当前计数器值,并将其与内部存储的最后一个值进行比较。不匹配的值表明需要做一些工作。

编辑:顺便说一下,我的进程是以不同的.exe:s执行的,不是从某个父进程创建的。操作系统是windows。

7 个答案:

答案 0 :(得分:2)

命名信号量怎么样? Posix支持它,不确定窗口。

答案 1 :(得分:1)

考虑您希望分发信息和潜在重叠的方式 - 如果任何读者完成阅读所需的时间比刷新所需的时间长,那么您将会遇到建议方法的麻烦。

我读到你的问题的方式,有多个读者,作者不知道(或大多数情况下)一次有多少读者,但想要通知读者有新的东西可供阅读。

在不知道有多少潜在读者的情况下,您无法使用简单的互斥或信号量来了解读者何时完成,而不知道每个人何时完成,您都没有关于何时重置事件以通知的良好信息为下一个阅读活动。

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 - 双重事件
假设任何1个读周期远小于写事件之间的时间。 创建2个手动重置事件,在任何时候最多1个事件将发出信号,在事件之间交替。信号将立即释放所有读者,一旦完成,他们将等待备用事件。

答案 2 :(得分:0)

你可以通过简单的方式或方式来做到这一点 简单的方法是在注册表或文件中存储共享值,以便所有进程同意经常检查它。

困难的方法是使用IPC(进程间通信,我使用的最常用的方法是NamedPipes。它不太难,因为你可以在网上找到大量关于IPC的资源。

答案 3 :(得分:0)

如果您使用* nix,则可以从named pipe(或套接字)读取进程,然后在那里写入特定的msg以告知其他进程应该关闭。

IPC performance: Named Pipe vs Socket

Windows NAmed Pipes alternative in Linux

答案 4 :(得分:0)

使用指定的事件对象手动重置。以下解决方案不会使用CPU,而是忙于等待

发送过程:

  • 设置活动
  • 睡10毫秒
  • 重置活动

接收流程:

  • 设置事件时所有等待进程都会通过
  • 他们阅读了文件
  • 让他们睡20码,所以说两次看不到同一个事件。
  • 再等一下

睡眠(10)实际上可能需要比睡眠(20)更长的时间,但这只会导致另一个循环(再次读取未更改的文件)。

答案 5 :(得分:0)

由于已知可执行文件的名称,我在几天前在项目中实现了另一种解决方案(在C#中): 每个读者进程都创建一个命名事件“Global \ someuniquestring_%u”,其中%u是它的进程ID。如果发出事件信号,请阅读文件并完成工作。 发件人进程有一个事件句柄列表,如果文件已更改,则将它们设置为活动状态,从而通知所有读取器进程。有时,例如当文件发生变化时,它必须更新事件句柄列表:

  • 获取名为'reader.exe'的所有进程(例如)
  • 每个流程都得到它的身份
  • 如果是新流程,请打开现有事件“Global \ someuniquestring_%u”的句柄。
  • 关闭所有不再运行进程的句柄。

答案 6 :(得分:0)

找到一个监控文件夹更改的解决方案(使用“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;
}