Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe to use volatile bool to force another thread to wait? (C++)

Everything I've read about volatile says it's never safe, but I still feel inclined to try it, and I haven't seen this specific scenario declared unsafe.

I have a separate thread that renders a scene, pulling data from the main simulation thread. This has no synchronization, and works fine.

The issue is that when the program exits, then renderer needs to stop pulling data from the simulation thread before the simulation thread can safely clean itself up without causing the renderer to attempt reading invalid memory.

To accomplish this, I have the renderer run infinitely in its thread:

volatile bool stillRendering;

void RenderThreadFunction()
{
    stillRendering = true;

    while(programRunning)
    {
        renderer->render();
    }

    stillRendering = false;
}

In the main program thread, when the windproc quit message is received, I do:

void OnQuit()
{
    programRunning = false;
    while(stillRendering)
    {
    }

    delete application;
}

The goal of this is to be sure the renderer stops pulling data from the application before calling delete on the application.

I first tried this without any volatile keywords, and it worked in debug mode, but in release mode it hung. I assume the compiler made some optimization that causes the program to stop checking the value of stillRendering.

Adding volatile to just stillRendering caused the application to successfully exit everytime I've tested it so far. I'm not certain why it doesn't seem to matter if "programRunning" is volatile.

Lastly, I am uncertain how the performance of the program will be impacted by using volatile for "stillRendering". It doesn't matter to me if making stillRendering volatile affects the performance of OnQuit(), but it does matter to me if it affects the performance of RenderThreadFunction()

like image 740
Matt Swarthout Avatar asked Feb 25 '13 18:02

Matt Swarthout


People also ask

Is volatile bool thread safe?

Updating a bool is always thread safe, if you never read from it. And if you do read from it, then the answer depends on when you read from it, and what that read signifies. On some CPUs, but not all, writes to an object of type bool will be atomic. x86 CPUs will generally make it atomic, but others might not.

Is volatile thread safe C?

In Java volatile creates a memory barrier when it's read, so it can be used as a threadsafe flag that a method has ended since it enforces a happens-before relationship with the code before the flag was set. This is not the case in C.

Does volatile ensure thread safety?

Therefore, the volatile keyword does not provide thread safety when non-atomic operations or composite operations are performed on shared variables. Operations like increment and decrement are composite operations.

Can volatile be reordered?

A number of readers asked whether making the read into a volatile read prevented the reordering problem. The answer to the general question of whether a volatile read can be re-ordered is yes, yes it can.


1 Answers

It's completely unsafe, although it might work with some compilers. Basically, volatile only affects the variable it's attached to, so RendererThreadFunction, for example, could set stillRendering false before having finished renderer->render();. (This is true even if both stillRendering and programRunning were both volatile.) The probablility of a problem is very small, so testing probably won't reveal it. And finally, some versions of VC++ do give volatile the semantics of an atomic access under C++11, in which case, your code will work. (Until you compile with a different version of VC++, of course.)

Given that renderer->render() almost certainly takes a non-negligible amount of time, there's absolutely no reason for not using a conditional variable here. About the only time you'd use volatile for this sort of thing is if the shutdown mechanism were triggered by a signal (in which case, the type would be sig_atomic_t, and not bool, although in practice, it probably doesn't make any difference). In that case, there wouldn't be two threads, but just the renderer thread and a signal handler.

like image 184
James Kanze Avatar answered Nov 11 '22 16:11

James Kanze