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.

Était-ce utile?

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top