Question

Hi I'm having a problem finding an answer to the question below. I'm trying to implement an application layer driver on Linux that performs some IO but needs to have some non-blocking interface functions. Essentially, there will only ever be two threads in this environment, Thread A and B.

Consider the following example:

Class Driver
{
    void foo()
    {
        emergency_shutdown = true;
        Signal(cond)
    }

    void thread_loop()
    {
        Lock(cond)
        while (true)
        {
            if (emergency_shutdown)
            {
                // Do an atomic IO Operation #1 that could take 5ms
                // For example: Send an emergency shutdown packet
                emergency_shutdown = false;
            }
            else
            {
                // do an atomic IO Operation #2 that could take 100ms
            }
            Signal(cond)
            CondWait(cond, 1000); // 1 second wait.
        }
        Unlock(cond)
    }
}        


Class HigherLayer
{
    ...

    powerfail_handler() // Function only has 20ms to run before power is lost
    {
        // POWER FAIL DETECTED!
        // Do some important stuff

        Driver::foo() // Force shutdown of device

        // Do some other important stuff

        // ... Power eventually lost but hopefully we did all the
        // important stuff in this function.
    }

    ...
}

In the above example.. Thread A is basically the Driver thread which is running 'thread_loop()' and Thread B is the HigherLayer thread which does a whole bunch of stuff as well as calling powerfail_handler if a powerfail is detected.

The main question is this: Is it ok for the driver function foo() to call Signal(cond) without Locking cond first? The reason I don't want to Lock cond is because I don't want any possible situation where the powerfail_handler would call foo() and it have to sit around for 100ms waiting for a lock to be released.

I understand the consequences of modifying the 'emergency_shutdown' variable outside of a Lock. They don't worry me too much.

I also understand that there will be some situations that if foo() is called during the 100ms window that IO Operation #2 is being done by Thread A, then my desired IO Operation #1 wont happen (because power will be lost before there's a chance to do it). That's fine too, I have no way around that and just have to live with it, but in that situation, I do NOT want to be blocked on foo() and miss out on doing the 'other important stuff' in Thread B (which is why I don't have a Lock in foo()).

I just want to make sure that if Thread A is Waiting (which should be the case 90% of the time) I want to signal it to stop waiting and do IO Operation #1.

So will the Signal() in foo() work as desired? If not, do I have to have it in a Lock? Also if not, are there any other ways to solve this problem?

Sorry for the wall of text and thanks ahead for your responses.

Was it helpful?

Solution

Is it ok for the driver function foo() to call Signal(cond) without Locking cond first?

Calling pthread_cond_broadcast() and pthread_cond_signal() while not holding a mutex is fine and portable:

The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal().


I understand the consequences of modifying the 'emergency_shutdown' variable outside of a Lock. They don't worry me too much.

At least use atomic operations to get/set the value of emergency_shutdown if you don't want to protect is with a mutex, atomics won't block your thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top