Cross-Platform Equivalent to Windows Events

Cross-Platform equivalent to windows events

I think a good, cross-platform equivalent to win32 events is boost::condition, so your code could look something like this:

void foo()
{
boost::mutex mtxWait;
boost::condition cndSignal;

bCall(boost::bind(&bar, mtxWait, cndSignal));

boost::mutex::scoped_lock mtxWaitLock(mtxWait);
cndSignal.wait(mtxWait); // you could also use cndSignal.timed_wait() here
}

void bar(boost::mutex& mtxWait, boost::condition& cndSignal)
{
doSomething();
cndSignal.notify_one();
}

Replacement for Windows specific HANDLE, Event Creation and Sync API in case of Linux

The replacement for CreateEvent is eventfd, you probably want EFD_CLOEXEC and EFD_NONBLOCK flags. Don’t use the semaphore flag unless you know what you’re doing.

The replacement for WaitForMultipleObjects is poll, specify the POLLIN flag in the requested events. Just keep in mind the event is not being reset by poll, it will stay signalled. Read 8 bytes from the eventfd handle to reset. The functionality is identical to manual-reset events on Windows.

To signal an event, call write on the eventfd handle, passing the address of a local uint64_t variable with value 1.

To destroy events once you no longer need them, just call close.

Update: I’ve just noticed you’re passing bWaitAll=TRUE to WaitForMultipleObjects.

Unfortunately, Linux poll can’t quite do that. It returns when timeout is expired, or when at least 1 handle becomes signaled, whichever happens first.

Still, the workaround is not too hard. You can emulate bWaitAll by calling poll multiple times in a loop until all of the events are signaled. No need to rebuild the array of handles, you can set file handle to a negative value for the events which became signaled after poll returned. Note that multiple of them may become signaled at once, poll return value tells how many of them did. Also don't forget to decrease the timeout value.

Is there a C++ cross platform named event like the CreateEvent() in Win32?

There is no built in way in C++ to do named events. But you can use boost to do it.

You're looking for boost::condition and boost::named_condition

As you also mentioned there exists: Poco.NamedEvent

Boost Equivalent for Windows Events

I think you need to use boost::mutex, boost::unique_lock, boost::condition_variable and possibly bool in order to imitate Events.

You actually might need sort of WaitForSingleObject in order to wait for an event. Might be like this:

void wait_for_user_input()
{
boost::unique_lock<boost::mutex> lock(mut);
while(!data_ready)
{
cond.wait(lock);
}
process_user_input(); // it might be not necessary to hold mutex locked here!!!
// if so just add curly braces like this:
// void wait_for_user_input()
// {
// {
// boost::unique_lock<boost::mutex> lock(mut);
// while(!data_ready) { cond.wait(lock); }
// }
// process_user_input();
// }

}

Can two different processes communicate with each other using Windows events in WINAPI?

Yes, it is possible. When one process creates a handle to an Event object, you have the option of assigning a name to that object in the kernel. The other process can then create/open its own handle to that Event object using the same name.

Note that to accomplish what you want, you actually would need 2 Events, eg:

writer.exe:

HANDLE hReadable = CreateEvent(NULL, FALSE, FALSE, TEXT("ReaderCanRead"));
if (!hReadable) ...

HANDLE hWritable = CreateEvent(NULL, FALSE, TRUE, TEXT("WriterCanWrite"));
if (!hWritable) ...

...

while (!quit)
{
...
WaitForSingleObject(hWritable, INFINITE);
if (quit) break;
// write int...
SetEvent(hReadable);
...
}

reader.exe:

HANDLE hReadable = CreateEvent(NULL, FALSE, FALSE, TEXT("ReaderCanRead"));
// or: HANDLE hReadable = OpenEvent(SYNCHRONIZE, FALSE, TEXT("ReaderCanRead"));
if (!hReadable) ...

HANDLE hWritable = CreateEvent(NULL, FALSE, TRUE, TEXT("WriterCanWrite"));
// or: HANDLE hWritable = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("WriterCanWrite"));
if (!hWritable) ...

...

while (!quit)
{
...
WaitForSingleObject(hReadable, INFINITE);
if (quit) break;
// read int...
SetEvent(hWritable);
...
}

That being said, you might consider using a named block of shared memory via CreateFileMapping()+MapViewOfFile(), rather than using a physical file.

However, there are many other Inter-Process Communication mechanisms that are way more suitable to your producer/consumer model than using a shared file/memory protected by Events. Pipes, sockets, mailslots, even window messages, would be a much better choice.

Is there a UNIX/pthreads equivalent to Windows manual reset events?

It's Linux-only (I only mention it because you have a "linux" tag), but I think you could build something like this on the futex syscall. See Ulrich Drepper's paper on Futexes for the gory details.

Very roughly, I envisage something along the lines of

void inline gate_wait(volatile int *gate)
{
if (*gate)
while (futex(gate, FUTEX_WAIT, 1, 0, 0, 0) == EINTR)
;
}

int inline gate_open(volatile int *gate)
{
*gate = 0;
return futex(gate, FUTEX_WAKE, INT_MAX, 0, 0, 0);
}

void inline gate_close(volatile int *gate)
{
*gate = 1;
}

If you do build this "gate" synchronisation primitive on top of futexes, it might be worth contributing it to Rusty Russell's userspace futex library.



Related Topics



Leave a reply



Submit