开发者

volatile and multithreading?

开发者 https://www.devze.com 2023-01-09 19:39 出处:网络
In the following code: #include <pthread.h> #include <unistd.h> #include <stdio.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

In the following code:

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int ready = 0;

wait()
{
    int i;
    do
    {
        usleep(1000);
        pthead_mutex_lock(&mutex);
        i = ready;
        pthread_mutex_unlock(&mutex);
    } while (i == 0);   
    printf("Finished\n");
}

signal()
{
 开发者_如何学JAVA   pthead_mutex_lock(&mutex);
    ready = 1;
    pthread_mutex_unlock(&mutex);
}

We spawn two threads we call wait in one thread and then call signal in the other We also get the compiler to optimize aggressively.

Now will the code behave as expected or will we need to make ready volatile to get this to work? Will different compilers and libraries handle this differently?

Edit: I am hoping that there might be something round the mutex functions that will prevent optimization around itself or that the compiler generally does not optimize round function calls.

Note: I have not compiled and tested the code yet, will do so when I have a chance.


Some perspective from the kernel kings:

http://kernel.org/doc/Documentation/volatile-considered-harmful.txt


I'd be surprised if the compiler assumes anything about a global variable in the presence of library function calls. That being said, volatile will not cost you anything, and it shows your intentions. I'd put it there.


Volatile is neither required nor sufficient. So there is no reason to use it. It is not sufficient because no standard specifies that it will provide visibility between threads. It is not necessary because the pthreads standard says mutexes are sufficient.

Worse, using it suggests that you are an incompetent programmer who tries to sprinkle magic dust over your code to get it to work. It smacks of cargo cult programming and anyone looking at the code will infer that you didn't know it wasn't required. Worse, they may think that you felt it was sufficient, and they'll be suspicious of any other code you have written, fearing you used "volatile" to hide multi-threading bugs rather than fixing them.


Now will the code behave as expected or will we need to make ready volatile to get this to work?

I would advise to use the volatile in the situation. Though in the case it seems it is not needed.

IOW, Personally I would have added volatile and removed the locking: it is not needed for setting/reading the variable's value.

Will different compilers and libraries handle this differently? I am hoping that there might be something round the mutex functions that will prevent optimization around itself or that the compiler generally does not optimize round function calls.

In your case the call to the function (pthread_mutex_lock()) has side effects and changes the execution environment. Thus compiler has to reread the global variable which might have being change by the call to the function.

To be really sure, you want to consult with C99's 5.1.2.3 Program execution where from I have borrowed the terminology. To give you the taste:

[...] Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place. (A summary of the sequence points is given in annex C.)

In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object). [...]

Excerpt from the annex C:

The following are the sequence points described in 5.1.2.3:
— The call to a function, after the arguments have been evaluated (6.5.2.2).

And from there on.

In my experience, compilers are sufficiently smart nowadays and even when optimizing aggressively wouldn't do anything fancy with loop control variable which is a global variable.


Volatile is needed here in the presence of optimization. Otherwise the read of ready can be legally moved out of the while loop.

Assuming limitations to optimization that are not promised by the standard may be fine now, but cause great grief to future maintainers as compilers improve.


yes, volatile int ready = 0; is always needed here.

Update
If you would like no optimization around some code snippet, you can either use #pragma directives around that code (if your compiler supports them) or - which is totally portable - move the code to separate files and compile these files with no or little optimizations.
The latter approach might still require usage of the volatile keyword, since the ready variable might be used by other modules which you might want to optimize.

0

精彩评论

暂无评论...
验证码 换一张
取 消