简体   繁体   中英

Creating global named counter shared between processes

How can I create a global counter-value that can be shared between multiple processes in 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. 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. Operating system is windows.

What about a named semaphore? Posix supports it, not sure about 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:

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.

See http://www.codeproject.com/KB/DLL/data_seg_share.aspx for more info.

// 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
Make your main app a com service where the workers can register with for events, push out the change to each event sink.

IPC - dual events
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. 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.

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.

IPC performance: Named Pipe vs Socket

Windows NAmed Pipes alternative in Linux

Use a named event object with manual reset . The following solution doesn't use the CPU so much than busy waiting

Sending process:

  • Set event
  • Sleep 10 ms
  • 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.
  • Wait again

Sleep( 10 ) might actually take longer than Sleep( 20 ) but this only results in another cycle (reading the unchanged file again).

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. 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)
  • For every process get it's id
  • Open a handle for the existing event "Global\\someuniquestring_%u" if it's a new process.
  • 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:

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM