0

The problem is that I have two threads. One thread only sets some request flags, and the other thread resets the request flags. Hence both threads have write access to the flags. I'm trying to do this without synchronization.

Here is what I've implemented, and I can't perceive how it might go wrong.

volatile uint32_t      g_FORM_Requests;



#define FORM_REQUEST(X)                                                       \
do {                                                                          \
  if (g_FORM_Requests)                                                        \
  {                                                                           \
    g_SHELL_Print("Server is busy executing previous requests...");           \
  }                                                                           \
  else                                                                        \
  {                                                                           \
    g_FORM_Requests=(X);                                                      \
  }                                                                           \
} while (0x00U)



void * SERVER_Thread( void * Data)
{
  uint32_t      Snapshot;

  while (!Done)
  {
    /*   Take a snapshot of requests. */
    Snapshot=g_FORM_Requests;
    Execute(Snapshot);
    g_FORM_Requests ^= Snapshot;
  }

  return (NULL);
}

The form issues requests to SERVER_Thread by calling FORM_REQUEST(X) macro. Each bit in g_FORM_Requests is an execution request flag for a separate task. The execution order of these tasks does not matter.

Am I right in assuming that it would work correctly? If not, where is the problem?

EDIT 1:

The volatile keyword makes sure that at the end of SERVER_Thread the g_FORM_Requests is read again before XORing it with Snapshot. This means if FORM_REQUEST() is interrupted in the middle of changing g_FORM_Requests, it would not cause erroneous behavior, because only the bits that are set in Snapshot will be removed from it.

The question is NOT if we can use volatile keyword as a barrier. I'm utilizing the fact that one of my threads only converts zeros to ones, and the other thread converts ones to zeros. Hence the g_FORM_Requests variable itself acts as a lock, and partial execution of the Critical Section in each thread is not problematic...

Mat
  • 116
  • 5
  • I know, It's not atomic. But I don't think that would cause a problem... Volatile is there to make sure at the end of SERVER_Thread, the g_FORM_Requests is read again before performing XOR. – Mat Dec 22 '16 at 12:52
  • This example is not using volatile keyword as a barrier. I'm using the fact that one one of my threads only converts zeros to ones, and the other thread converts ones to zeros. – Mat Dec 22 '16 at 13:14
  • I read the linked post, and I still don't get it why did you close this question? It's not a duplicate... – Mat Dec 22 '16 at 13:26
  • 1
    The problem isn't visibility, it's ordering. There is nothing to guarantee the xor will occur **after** the call to Execute. – John Q. Dec 22 '16 at 13:40
  • Execute only uses the snapshot. The g_FORM_Requests is not accessed... – Mat Dec 22 '16 at 13:51
  • 3
    The xor is a read-modify-write, i.e., three distinct operations. Consider this: thread one enters the assign block, but before it can write, thread two loads Snapshot with zero. The xor loads gForm (still zero) and xors it with Snap resulting in zero. Now thread one finally assigns the request to gForm in thread one, only to be immediately overwritten by zero in thread two. – John Q. Dec 22 '16 at 17:14
  • You are right. Thank you... :) – Mat Dec 22 '16 at 20:28
  • 1
    @JohnQ.: Another possible duplicate target: [Can `num++` be atomic for 'int num'?](http://stackoverflow.com/questions/39393850/can-num-be-atomic-for-int-num/39396999#39396999). That explains exactly why read-modify-write ops aren't atomic "by default", unlike separate stores and loads, even if they happen to compile to a single memory-destination x86 instruction. (The C memory model still disallows concurrent write+read of non-atomic variables, of course, and provides `memory_order_relaxed` for when you need atomicity but not ordering). – Peter Cordes Dec 28 '16 at 05:09

0 Answers0