tags:

views:

481

answers:

4

One programming construct I use quite a bit in LabVIEW is the Event Structure. This gives me the benefit of not having to needlessly waste CPU cycles via polling but only perform actions when an event I'm interested in is generated.

As an experienced LabVIEW programmer with a decent understanding of C, I'm curious how one would go about emulating LabVIEW's event structure in C; preferably under Linux. A small code sample (like the one in the link above) illustrating how this might be done would be much appreciated. Also, if there already exists 3rd party libraries (for Linux) to add this event framework to C, that would be nice to know as well. Thanks.

+4  A: 

The Event Structure is really just an abstraction that hides the thread of execution from you. There has to be some code running somewhere on the computer that is checking for these events and then calling your event handlers. in C, you'd be expected to provide this code (the "main loop" of the program) yourself. This code would check the various event sources you are interested in and call your event handler functions.

The trick then becomes how to not have this main loop wildly spinning the CPU. One easy trick is to have the main loop sleep for a period of time and then check if any events need to be handled, and then sleep again. This has the downside of introducing latency. A better trick, when applicable, is to have the Operating System do these checks as part of its normal operations, and then wake your application's main loop up when something interesting happened. In Linux, this is done with the 'select' system call, but select has the limitation that it can only specify a resource that can be associated with a file descriptor, so devices, stdin, files, network ports are fine.

Edit: To clarify for my downvoters: I am not denying the existance of hardware interrupts. Yes, in cases where code has direct access to hardware interrupts for all events that it wishes to handle (such as an embedded system or device driver) you can write truly "event driven" code with multiple entry points that does not busy wait or sleep. However, in a normal application level C program running under Linux, this code architecture does not literally exist but is emulated at the application level. Any Linux application is going to have a main loop, and at least one thread of execution. This thread may get paused by the scheduler, but it always exists and always has an instruction pointer at a particular instruction. If the code leaves the main() the program ends. There is no facility for the code to return from main and get a callback later on from the kernel. The code has a single entry point and must call its various event handlers manually. Other than in a device driver (or very specific system code using signals), you can not have the kernel or hardware automatically call a certain function if the user clicked on a certain menu item, instead your code is running, detects this event itself, and calls the correct event handler.

You can tell LabView "Call this function when XX happens". In C, you tell your own event dispatch code "Call this function when XX happens".

What I'm trying to say (poorly?) is that the Event framework architecture is not native to a C / Linux application. It must be emulated by your code by having a main dispatch thread that gives the appearance of an event driven framework. Either you do this manually, or use an event library that does this behind the scenes to give the appearance of an event driven model. LabView takes the second approach, so it appears that no code is running when no events are happening, but in reality there is LabView's own C++ code running managing the event queues. This doesn't mean that it is busy waiting all the time, as I said before there are system calls such as select and sleep that the code can use to yield cpu time when it has no work to do, but the code can not simply stop executing.

Lets say you want to write an "event driven" program with two event handlers. One that gets called every ten seconds called tick() and one that gets called every time a key gets pressed called key(), and one that gets called everytime the word "foobar" gets typed called foobar(). You can define these three event handlers, but in addition you need some dispatch main thread that basically does

 while not quitting
   If 10 seconds have elapsed, call tick()
   If Key has been Pressed
       call key() 
       add save the key to our key buffer
       If buffer now contains "foobar" call foobar() and clear buffer
   Wait()

If all of the events you care about are system level events or time level events, you can Wait() can simply be telling the kernel 'wake me up when one of these things happens' so I don't need to 'busy wait', But you can't simply tell the Kernel "call foobar() when "foobar is pressed". You have to have application level dispatch code that emulates the Event Structure. You're C program only has a single entry point from the kernel for each thread of execution. If you look at libraries that provide event dispatch models, such as Qt, you will find that they are working like this under the hood.

bdk
Polling is not necessary if the hardware provides an adequate interrupt mechanism and the OS supports it. No one likes to busy wait.
dmckee
Definately true. I considered putting in a clause about the special case for interrupt handlers, but figured it wasn't really helpful for the problem the question is trying to solve.. If your code is running at the application layer and not in the kernel, you don't have direct access to interrupt callbacks. Instead, you get your notifications from the interrupt handler indirectly via the select system call mentioned above.
bdk
Unfortunately, most hardware is interrupt-based. Devices which *are* polled are polled in response to a periodic timer interrupt on any remotely modern OS.
Potatoswatter
@bdk I'm a bit confused because on multiple LabVIEW training sessions they specifically contrast the Event Structure with polling. To add to that I can physically see the difference in CPU usage between using the event structure and polling with a wait statement. I find it hard to believe that polling is going on behind the scenes because in order to get the CPU usage via polling as low as I get with events, my response time goes through the roof since I have to wait/sleep for so long.
SiegeX
That's because polling in whatever language LabVIEW is implemented in (C++ if I'm not mistaken) is far more efficient than polling in LabVIEW itself.
ptomato
The underlying implementation LabVIEW uses may use constructs to sleep or wait for hardware interrupts for certain device related events such as waiting for serial input, in which case the application is most likely waiting on a select call and not using any CPU. However, for high level events such as "Clicked on File Menu", there is no way for the code to just sleep and wait for some hardware interrupt to come in for the event. Instead, code inside the app has to watch the low level mouse events and generate high level events. In LabView this is done "under the hood" instead of in your code.
bdk
In any case, the first sentence "The Event Structure is really just an abstraction that hides the polling from you." is wrong and highly misleading and should be taken out. It abstracts from select() or something similar, not from polling.
reinierpost
@reinerpost: Thanks, I clarified answer. I think your right that it was misleading. On Linux, the syscalls are pretty much the same-- Look at the man page for the poll() syscall on a Unix machine. It is almost identical in functionality to select(). In fact, one call is often just a wrapper around the other. In that context saying that something abstracts on poll() or select() is really splitting hairs. However outside of this terminology, the term polling is commonly used interchangably 'busy waiting', so I think thats where I was going astray.
bdk
@bdk: Thank you for your updated response. I will definitely look into the select() call to see how this works. In the interim though, I read up on signals and threw this code together http://codepad.org/voFxsStr which seems to approximate an Event structure pretty well. However, I have a feeling that in my quest to make the parent event driven, I have merely moved the unavoidable processing you speak of to the child, is this correct? Word of caution, the code works fine on the first iteration but goes wacky after that if you don't press 'q' on the 2nd. Curious as to why, but not on topic.
SiegeX
+2  A: 

I like libev for this sort of thing.

Jack
A: 

If all you care about is keyboard input, C standard I/O is what you want. By default input streams are buffered and will stall your program until input is received. Use scanf, getchar, whatever else in <stdio.h>.

If you want mouse input, you'll need to be more specific about your platform as C/C++ has no native support for the mouse or windows.

Potatoswatter
+1  A: 

Most GUI toolkits (GTK, Qt, etc.) implement their own abstraction of an event loop. I've pastebinned a sample program here, because it was a bit long to include in the answer. It's a port of the LabVIEW example you mentioned to C using the GTK toolkit, because that's the one I'm familiar with. The basics of the event loop are not much different in other toolkits, though.

ptomato