Hi, In the example you give, you are basically protecting accesses to the volatile global variable error with mutexes.
I don't believe that these mutexes are necessary. The accesses to the variable error are already atomic, and the volatile keyword will ensure that the compiler does not hold the variable in a register. They might help your program work on all platforms by ensuring that the appropriate memory barriers are inserted. However, that would be a side-effect. The problem I have with the code is that there is no synchronisation on the passing of the barrier between the threads. The synchronisation should be something like: mutex_lock() write to shared_buf mutex_unlock() That's the structure that you don't want another thread to read whilst it is partially complete. If you get that synchronisation correct, I expect that the synchronisation on the error variable would also be attained. Note that your definition of type_p is incorrect, it needs to be defined as a pointer to a volatile variable. The fact that it is made to point to the first elements in a volatile shared_buf does not transmit that volatility onto the pointer. The code would probably work because in the example you are immediately do a function call after the write - which would ensure that the compiler writes the variable to memory (in case the function reads it). HTH, Darryl. On 03/21/09 12:06 AM, Bert Miemietz wrote: > Hallo Darryl, > > after some more reading (your links were really interesting) I hope you don't > mi > nd > if I come around with one more question. Perhaps the following code fragments > can serve as an example: > > #define USE_MTX > #define BSIZE 8192 > > volatile int error; > volatile char shared_buf[BSIZE] /* buffer for data transport */ > int *type_p /* describe type of data in buffer */ > type_p = (int *) shared_buf; > pthread_mutex_t mtx; > > pthread_create(..., transmit_thread, ...); > pthread_create(..., receive_thread, ...); > pthread_create(..., consumer_thread, ...); > > transmit_thread { > int error1; > > while (1) { > #ifdef USE_MTX > pthread_mutex_lock(&mtx); > error1 = error; > pthread_mutex_unlock(&mtx); > #else > error1 = error; > #endif > if (error1 != 0) break; > if (transmit() != 0) { /* transmit yields any error */ > #ifdef USE_MTX > pthread_mutex_lock(&mtx); > error = 5; > pthread_mutex_unlock(&mtx); > #else > error = 5; > #endif > } > } > } > > receive_thread { > int error1; > > while (1) { > #ifdef USE_MTX > pthread_mutex_lock(&mtx); > error1 = error; > pthread_mutex_unlock(&mtx); > #else > error1 = error; > #endif > if (error1 != 0) break; > if (receive_to_buf() != 0) { /* receive yields any error */ > #ifdef USE_MTX > pthread_mutex_lock(&mtx); > error = 5; > pthread_mutex_unlock(&mtx); > #else > error = 5; > #endif > } > else { > *type_p = 10; > wakeup_consumer_with_cv(); > } > } > } > > > consumer_thread { > int error1; > waiting_on_cv(); > #ifdef USE_MTX > pthread_mutex_lock(&mtx); > error1 = error; > pthread_mutex_unlock(&mtx); > #else > error1 = error; > #endif > if (error1 == 0) { > if (*type_p == 10) { > process_the_buffer(); > } > } > } > > > I hope, I didn't do any simple mistakes in writing. > The following is desired: > - transmit and receive threads share the same communication > and shall work in parallel > - as soon as any error occurrs this would result in > interrupting the threads in their transmit/receive functions > The fact that this is due to an error shall be > communicated by means of the variable error. A thread > interrupted in transmit or receive shall never retry any > transmit or receive > - if the receive thread has filled the buffer it wakes up > the consumer waiting on a cv. The consumer shall then > find the correct data in the buffer (as long as error is 0). > > It is not worth discussing the purpose of the code. It is only > an example to make clear my issue. If I really need a mutex > or similar around any access to error (just to ensure flushing > of the store buffers after an update) this leads to an ugly > code instead of simply writing "while (error == 0)". Error is > not calculated, it is simply assigned a value. Therefore I > guess one could simply use "error = 5" without a mutex > if only this got visible right away to all other threads. > On the other hand: If I use the mutex would I still need > the volatile keyword to ensure the compiler doesn't > optimize away the access? > And how can I be/make sure that data written to buffer > by receive_thread is completely visible to consumer_thread > after the latter is woken up with the cv? > Perhaps all these questions can be condensed to the question > if I need to define USE_MTX in the example to get a conforming > and portable code that runs on any CPU (at least with Solaris). > > I hope very much that these issues are also of interest > to other programmers. > Thank you in advance for your patience and your assistance! -- Darryl Gove Compiler Performance Engineering Blog: http://blogs.sun.com/d/ Book: http://www.sun.com/books/catalog/solaris_app_programming.xml