-1

There is a singleton service class ItemsDataSource: IItemsDataSource injected into many other classes (business domain classes)

These business domain classes are many and run asynchronously calling methods on that ItemsDataSource service.

public interface IItemsDataSource
{
    Task<IEnumerable<string>> GetItemsAsync();
    void SetSourceConfiguration(JToken src);
}

public class ItemsDataSource : IItemsDataSource
{
    private JToken m_configuration;
    public Task<IEnumerable<string>> GetItemsAsync()
    {
        // Use m_configuration to some items
    }
    public void SetSourceConfiguration(JToken config)
    {
        m_configuration = src;
    }
}

When multiple classes that are using this service are running asynchronously (let's say on 2 threads T1 and T2), this is sometimes happening:

T1 calls SetSourceConfiguration(config1) then starts running GetItemsAsync() asynchronously. T2 calls SetSourceConfiguration(config2) (m_configuration is now assigned with config2) before T1 is done running GetItemsAsync(). For that T1 uses config2 instead of config1 and unexpected behavior happens.

The questions:

1- The optimal fix I think is removing SetSourceConfiguration and passing the JToken config directly as parameter into GetItemsAsync, or locking the code in the business classes, or is there another better solution ?

2- Which design pattern violation caused this bug ? So It could be avoided in the first place.

3- What is the "technical" term for this bug ? Methods with Side Effects, Design pattern violation, etc. ?

EEAH
  • 715
  • 4
  • 17
  • 1
    Re, "Which design pattern violation caused this bug ? So It could be avoided in the first place." You aren't going to write bug-free code by paying attention to "design patterns." You have to pay attention to your own code. You have to think carefully about what it does. (E.g., what does it mean when two threads each want to set the same global variable to a different value.) Design patterns are just that: patterns that programmers tend to use again and again. Giving them names makes it easier for us to explain how our own code works when we happen to use one. – Solomon Slow Sep 30 '22 at 15:13

1 Answers1

0

1- The optimal fix I think is removing SetSourceConfiguration and passing the JToken config directly as parameter into GetItemsAsync, or locking the code in the business classes, or is there another better solution ?

If your service ItemsDataSource is not singleton service, you can remove SetSourceConfiguration and passing the JToken config directly as parameter into GetItemsAsync. However, it is singleton service, so the way to go, imho, is using lock of critical section.

The code would look like this, if you are using C#.

private readonly object myLock = new object();

public void Foo()
{
    lock (myLock )
    {
        // critical section of code here
    }

}

Read more about lock here

2- Which design pattern violation caused this bug ? So It could be avoided in the first place.

It is not pattern. It is race condition. A race condition occurs when two or more threads can access shared data and they try to change it at the same time.

3- What is the "technical" term for this bug ? Methods with Side Effects, Design pattern violation, etc. ?

It is race condition.

StepUp
  • 36,391
  • 15
  • 88
  • 148
  • For point number 1, why the way to go is using a lock ? that would make an async code sync. Which benefits does it have vs passing the configuration to the GetItemsAsync ? – EEAH Oct 02 '22 at 12:52
  • @EEAH lock prevents race condition. If you feel that my reply is helpful, then you can upvote or mark my reply as an answer to simplify the future search of other users. [How does accepting an answer work?](https://meta.stackexchange.com/a/5235/309682) – StepUp Oct 02 '22 at 12:56