title: Race Condition - Can Mutexes Be More Flexible?
body: <p>I have a TThread object named <strong>TTestThread</strong>. When the threads are created, they make a local copy of the global configuration variables. The user is allowed to change the global configuration variables at any time, and when he does so, all threads are notified of the change via their local <strong>UpdateLocalCopyOfConfigVariables</strong> variable. The threads don't rely on the global configuration variables directly because they can be modified at any point by the user, which would create a race condition if the threads were to access them at the same time.</p>
  
  <p>Here's <strong>TTestThread</strong>:</p>
  
  <pre><code>type
    TTestThread = class(TThread)
    private
      LocalConfigA : String;
      LocalConfigB : Integer;
      procedure UpdateLocalConfigIfNecessary;
    protected
      procedure Execute; override;
    public
      UpdateLocalCopyOfConfigVariables : Boolean;
      constructor Create;
    end;
  
  implementation
  
  constructor TTestThread.Create;
  begin
    inherited Create(false);
    UpdateLocalCopyOfConfigVariables := true;
  end;
  
  procedure TTestThread.UpdateLocalConfigIfNecessary;
  begin
    WaitForSingleObject(ConfigurationLocker, INFINITE);
    if (UpdateLocalCopyOfConfigVariables) then
    begin
      LocalConfigA := GlobalConfigA;
      LocalConfigB := GlobalConfigB;
      UpdateLocalCopyOfConfigVariables := false;
    end;
    ReleaseMutex(ConfigurationLocker);
  end;
  
  procedure TTestThread.Execute;
  begin
    while (not(Terminated)) do
    begin
      UpdateLocalConfigIfNecessary;
      // Do stuff
    end; 
  end;
  </code></pre>
  
  <p>As you can see, I have a mutex in place to avoid the sort of race condition described earlier. <strong>WaitForSingleObject(ConfigurationLocker, INFINITE);</strong> is called when the user changes the global configuration variables:</p>
  
  <pre><code>procedure ChangeGlobalConfigVariables(const NewGlobalConfigA : String ; NewGlobalConfigB : Integer);
  var
    I : Integer;
  begin
    WaitForSingleObject(ConfigurationLocker, INFINITE);
  
    GlobalConfigA := NewGlobalConfigA;
    GlobalConfigB := NewGlobalConfigB;
  
    for I := 0 to ThreadList.Count - 1 do
      TTestThread(ThreadList[I]).UpdateLocalCopyOfConfigVariables := true;
  
    ReleaseMutex(ConfigurationLocker);
  end;
  </code></pre>
  
  <p>The thing is, while it prevents the threads from updating their local copy of configuration variables at the same time the global configuration variables are being changed, it also prevents two threads from updating their local configuration at the same time – even if the global configuration variables are not being changed. As far as I know, race condition is an issue when there's writing going on. If the global configuration variables are the same, then the threads can all update their local copy at the same time with no issues.</p>
  
  <p>Am I right? If so, is there a way to fix this issue? Granted, it's not a big one, but I still feel like there has to be a better solution...</p>