Avoid or mitigate race condition for two functions sharing same variable (resource) in C#

143 views Asked by At
  • I have two functions in different classes, and they are generating race condition.

  • One function is updating variables value and another one is using variable, and they are in Race condition my assumption.

  • counter variable is accessible from both functions. var counter=0;

  • Both functions are in different classes.

Function updating value

protected void updateValue(SomeClassType val){
  // Based upon some condition value for variable is updated
  if(val.id){ // some condition
    counter=2;
  }
}

Function using value

protected void useValue(var counter){
  // Do something with variable.
}
  • The upateValue function is running in worker-thread. and useValue is running in main-thread.
  • What I need is useValue should wait till updateValue, updates variable value.

What I Tried

  • Created one static object of AutoResetEvent.
public static AutoResetEvent autoResetEventForUpdateValue = new AutoResetEvent(false);
protected void updateValue(SomeClassType val){
  // Based upon some condition value for variable is updated
  if(val.id){ // some condition
    counter=2;
  }
  autoResetEventForUpdateValue.Set();
}

Function using value

WaitHandle[] waitHandles = new WaitHandle[] { autoResetEventForUpdateValue};
protected void useValue(var counter){
  // Do something with variable.
}

Also updateValue(val), this parameter val of type SomeClassType is not accessible in implementation of class useValue(counter).

  • With my solution while debugging I realized that useValue keep waiting and updateValue is not initialized as worker-thread not running there.
1

There are 1 answers

3
JonasH On

I would just change UpdateValue to return the value instead of updating it in place, that should make ordering trivial:

var currentCounterValue = ...
var updatedCounterValue = await Task.Run(() => ComputeNewCounterValue(currentCounterValue));
UseValue(updatedCounterValue );

Pure methods, i.e. methods without side effects, where the result only depend on the input, tend to be the easiest to use. This is especially true when dealing with multi threading.

You might also want some mechanism to ensure your method cannot run concurrently. If this is triggered by a button press you could disable the button before you call ComputeNewCounterValue and enable it after UseValue;