views:

1038

answers:

5

I have a single HW interface I want to use from two applications (processes) on the same workstation. The HW requires a single initialization call then either app uses the same function (in the same library) to do many transactions with the HW.

So each app should act like this:

main()
    // I don't know if another app already init'ed the HW
    ret = hw_init_lock(non-blocking)

    if ret = OK
        // no one else has done this, I have to
        init_hw()
    else
       //someone else has already init'ed the HW, I gotta make sure it stays that way
       //as long as I'm alive
       increment_hw_init_ref_counter()

    hw_trans_lock(blocking)
    hw_trans()
    hw_trans_unlock()
    ....

    //exit app, uninit hw if we are last out
    ret = decrement_hw_init_ref_counter()
    if ret == 0
        uninit_hw()

    exit(0)

What is the mechanism I can use in the lock and reference count calls that is shared between two applications? I'm thinking named pipes i.e. mkfifo().

+2  A: 

Use the POSIX semaphores.

florin
+2  A: 

Since you only need a semaphore count of one, a mutex suffices.

kenny
POSIX semaphores can be shared across unrelated processes, while pthread mutexes cannot.
ephemient
+4  A: 

POSIX semaphore is the way to go. Since you want to share the same semaphore across processes, you need to use a named semaphore.:

A named semaphore is identified by a name of the form /somename. Two processes can operate on the same named semaphore by passing the same name to sem_open(3).

albertb
A: 

I assume that

...that is shared between two applications?

means that you want these two things to be running as separate processes? If that's not true, and they are running as a single process (with multiple threads), then the suggestions of semaphores and mutexes are the best option and should be quite straightforward.

Note that the answer will depend on exactly how you're accessing this hardware. For example, if it's exposed through a file then normal file locking can be used.

However if you're attempting to synchronise access to the hardware across two processes that's a different matter. I guess the first thing to say is that it's going to be easier to synchronise, if you can, to have a single process in charge of accessing the hardware. In this model you might have one process that acts as a server for the hardware - accepting requests from other processes and performing the reads and writes on their behalf. Just about any form of interprocess communications will be suitable, but for simplicity something like the message queue (link) may be appropriate with some appropriate data structure (eg. a flag to indicate whether it's a read or write operation, offset from base address of your hardware, number of bytes, buffer (in case of a write))

If putting all of the direct hardware access into a single process isn't appropriate then you'll have to use a proper synchronisation scheme. I would investigate the use of either file locks (and implement a rudimentary mutex scheme), or using named semaphores (as albertb has suggested)

Andrew Edgecombe
+2  A: 

Semaphores and Mutexes/condition variables are good, very high-performance primitives which are appropriate for use in between threads or in between processes.

All of these are based on the idea (and usually, on the reality) of test-and-set or other atomic operations performed upon shared memory.

If you expect to distribute your processes over the network, then semaphores and mutexes may not be right for you--they only work on a single machine. Pipes and sockets are more generally network-extensible.

A brief summary of mutexes, condition variables and semaphores:

Mutexes

A mutex is a primitive which can be either locked, or unlocked. The process/thread which locked it must be the one to unlock it. This ownership aspect allows the operating system to apply some interesting optimizations, such as priority inheritance and priority ceiling protocol (to avoid priority inversion). however, the mutex does not have a count associated with it. You can't lock an already locked-mutex, in general, and retain memory that it was "locked twice" (there are some extensions that allow this, I think, but they are not available everywhere)

Condition Variables

A mutex is great for...well, MUTual EXclusion. But what if you need to block on a condition associated with the object to which you have mutual exclusion? For this, you use a condition variable, or CV. A CV is associated with a mutex. For example, say I have a queue of input data which my processes want to access. One grabs the mutex so it can look at the queue without fear of interference. However, it finds the queue empty and wants to wait for something to come in on the queue. It therefore waits on the "queue not empty" condition variable. The interesting part here is that, because the CV is associated with the mutex, the mutex gets automatically re-acquired once the condition variable is signalled. Thus, once the process wakes up after waiting on the CV, it knows that it has exclusive access again to the queue. What it does not know is whether the queue really has anything on it--perhaps two processes waited on the CV--one thing came in--and the first priority got in and dequeued the "thing" before the second thing woke up. Thus, whenever you use a CV, you need to RECHECK the condition, like this:

mutex_enter(m);
while (! condition) {
   cond_wait(m, c); // drop mutex lock;  wait on cv;  reacquire mutex
}
//processing related to condition
mutex_exit(m);

Semaphores

OK, that is mutexes and condition variables. Semaphores are simpler. They can be incremented and decremented by any processes. They have memory--they count--so you can use them to determine how many of a condition have occurred. Not so with condiiton variables. Also, because semaphores can be decremented by one process and incremented by another, they do not have the ownership aspect--so no priority inheritance, no priority inversion avoidance is possible.

Now, finally--all of these mechanisms require shared memory for an efficient implementation. This may be fine for you, but be aware--if you believe that your appliction may eventually be distributed, then mutexes, condition variables and semaphores may not be for you. Pipes and sockets, while much higher-overhead, have the possibility of being extended over the network fairly straightforwardly.

bog