简体   繁体   English

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

[英]Creating global named counter shared between processes

How can I create a global counter-value that can be shared between multiple processes in c++? 如何在c ++中创建可以在多个进程之间共享的全局计数器值? What I need is a way to "invalidate" multiple processes at once, signaling them to perform some operation (like reading from file). 我需要的是一种使多个进程立即“无效”的方法,以信号通知它们执行某些操作(例如从文件读取)。 All processes would continuously poll (every 10ms) for current counter-value and compare it with internally stored last value. 所有进程都将连续轮询(每10ms)以获取当前计数器值,并将其与内部存储的最后一个值进行比较。 Mismatching values would indicate that some work is needed. 值不匹配将表明需要做一些工作。

Edit: btw my processes are executing as different .exe:s, not created from some parent process. 编辑:顺便说一句,我的进程正在执行为不同的.exe:s,而不是从某些父进程创建的。 Operating system is windows. 操作系统是Windows。

What about a named semaphore? 命名信号量呢? Posix supports it, not sure about windows. Posix支持它,不确定Windows。

Consider the way you want to distribute the information and potential overlaps - if it takes longer for any of the readers to finish reading than it takes for a refresh then you are going to get in trouble with the suggested approach. 考虑一下您要分配信息的方式和潜在的重叠-如果任何读者完成阅读所花的时间比刷新所花费的时间长,那么您将在建议的方法中遇到麻烦。

The way I read your question, there are multiple readers, the writer doesn't know (or care in most part) how many readers there are at one time, but wants to notify the readers that something new is available to read. 我阅读问题的方式有很多读者,作者不知道(或在大多数情况下)一次有多少读者,但想通知读者有新内容可供阅读。

Without knowing how many potential readers there are you can't use a simple mutex or semaphore to know when the readers are done, without knowing when everybody is done you don't have good info on when to reset an event to notify for the next read event. 如果不知道有多少潜在的读者,就无法使用简单的互斥或信号量来了解何时完成阅读器,不知道每个人何时完成,就无法掌握何时重置事件以通知下一个事件的好信息。读取事件。

MS Windows specific: MS Windows特定:

Shared Segments 共享的细分
One option is to place variables within a shared data segment. 一种选择是将变量放置在共享数据段中。 That means that the same variables can be read (and written to) by all exe's that have named the same segment or if you put it into a DLL - loaded the shared DLL. 这意味着,具有相同段的所有exe都可以读取(或写入)相同的变量,或者将其放入DLL中-加载共享的DLL。

See http://www.codeproject.com/KB/DLL/data_seg_share.aspx for more info. 有关更多信息,请参见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 IPC-COM
Make your main app a com service where the workers can register with for events, push out the change to each event sink. 使您的主应用成为com服务,工作人员可以在其中注册事件,然后将更改推送到每个事件接收器。

IPC - dual events IPC-双重事件
Assuming any 1 read cycle is much less than time between write events. 假设任何一个读周期都比写事件之间的时间短得多。 create 2 manual reset events, at any time at most 1 of those events will be signaled, alternate between events. 创建2个手动重置事件,在任何时候最多会发信号通知其中一个事件,并在事件之间交替。 signaling will immediatly release all the readers and once complete they will wait on the alternate event. 信令将立即释放所有阅读器,完成阅读后,他们将等待替代事件。

you can do this the easy way or the way the easy way is to store shared values in registry or a file so that all processes agree to check it frequently. 您可以使用简便的方法,也可以使用简便的方法将共享值存储在注册表或文件中,以便所有进程都同意经常检查它。

the hard way is to use IPC(inter process communication, the most common method that i use is NamedPipes. its not too hard because you can find plenty of resources about IPC on the net. 困难的方法是使用IPC(进程间通信,我最常用的方法是NamedPipes。它不太难,因为您可以在网上找到很多有关IPC的资源。

If you are on *nix you could make the processes read from a named pipe (or sockets), and then write the specific msg there to tell the other processes that they should shutdown. 如果使用* nix,则可以使进程从命名管道 (或套接字)中读取,然后在其中写入特定的msg,以告知其他进程应关闭它们。

IPC performance: Named Pipe vs Socket IPC性能:命名管道与套接字

Windows NAmed Pipes alternative in Linux Windows NAmed Pipes在Linux中的替代方案

Use a named event object with manual reset . 使用具有手动重置功能的命名事件对象。 The following solution doesn't use the CPU so much than busy waiting 以下解决方案使用CPU不如忙等待

Sending process: 发送过程:

  • Set event 设定事件
  • Sleep 10 ms 睡眠10毫秒
  • Reset Event 重设活动

Receiving processes: 接收流程:

  • All waiting processes pass when event is set 设置事件后,所有等待的过程都会通过
  • They read the file 他们读了文件
  • Let them sleep for 20 ms, so say can't see the same event twice. 让他们睡眠20毫秒,因此说两次无法看到同一事件。
  • Wait again 再等一下

Sleep( 10 ) might actually take longer than Sleep( 20 ) but this only results in another cycle (reading the unchanged file again). Sleep(10)实际上可能比Sleep(20)花费更长的时间,但这只会导致另一个周期(再次读取未更改的文件)。

As the name of the executable is known, I have another solution which I implemented (in C#) in a project just a few days ago: Every reader process creates a named event "Global\\someuniquestring_%u" with %u being it's process id. 由于可执行文件的名称是已知的,所以几天前我在一个项目中用C#实现了另一个解决方案:每个读取器进程都创建一个命名事件“ Global \\ someuniquestring_%u”,其中%u是它的进程ID。 。 If the event is signaled, read the file and do the work. 如果发出事件信号,则读取文件并进行工作。 The sender process has a list of event handles and sets them active if the file has changed and thus notifys all reader processes. 发送者进程具有事件句柄列表,如果文件已更改,则将它们设置为活动状态,从而通知所有读取器进程。 From time to time, eg when the file has changed, it has to update the list of event handles: 有时,例如,当文件已更改时,它必须更新事件句柄列表:

  • Get all processes with name 'reader.exe' (eg) 获取名称为“ reader.exe”的所有进程(例如)
  • For every process get it's id 为每个进程获取它的ID
  • Open a handle for the existing event "Global\\someuniquestring_%u" if it's a new process. 如果它是一个新进程,请为现有事件“ Global \\ someuniquestring_%u”打开一个句柄。
  • Close all handles for no longer running processes. 关闭不再处理的所有句柄。

Found one solution for monitoring folder changes (with "event_trigger"-event) and reading additional event information from file: 找到了一种监视文件夹更改(使用“ 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