1

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.

6
  • Why don't you just use an event object?
    – wj32
    Commented Nov 23, 2010 at 19:35
  • @wj32: Like mutex? It signals only one process at the time.
    – AareP
    Commented Nov 23, 2010 at 19:46
  • This seems like single writer with multiple readers each reading every write. Is that what you want? Commented Nov 23, 2010 at 23:40
  • 1
    @AareP: event object, not mutex. But looking at your other comments, you should probably be using an I/O completion port or something, to queue work.
    – wj32
    Commented Nov 24, 2010 at 4:42
  • @AareP: Do you know the executable names of the processes?
    – ur.
    Commented Nov 24, 2010 at 7:59

7 Answers 7

2

What about a named semaphore? Posix supports it, not sure about windows.

1
  • With semaphores WaitForSingleObject() call would decrease semaphore's value for each process, and the amount of processes running at one time is arbitrary.
    – AareP
    Commented Nov 23, 2010 at 19:55
1

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.

0

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.

1
  • Yeah, finding information about IPC is easy, it's understanding it what's difficult. :)
    – AareP
    Commented Nov 23, 2010 at 19:53
0

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

2
  • Actually I was wondering how those pipes work. What happens when there are multiple readers at the receiving side of the pipe? Messages will be distributed in FIFO order?
    – AareP
    Commented Nov 27, 2010 at 8:41
  • For multiple readers, you should use sockets instead: stackoverflow.com/questions/1634580/… Commented Nov 27, 2010 at 14:38
0

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).

1
  • Actually my processes are not just waiting for event. There's other stuff they are busy with also. So I can't say whether it will take 10ms or 1000ms for them to check the event status.
    – AareP
    Commented Nov 23, 2010 at 20:16
0

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, e.g. when the file has changed, it has to update the list of event handles:

  • Get all processes with name 'reader.exe' (e.g.)
  • 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.
0

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.