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

Reply via email to