madmurphy
madmurphy

Reputation: 1821

When to use a mutex and when not

I have a global variable named my_list containing a linked list (i.e., the variable is a pointer to the first member of the list). This variable can be edited only by two threads, thread A and thread B. In case the list becomes empty, the variable is set to NULL. When this happens the variable is set to NULL first, and afterwards the memory is freed.

As it is edited by two threads, I use a mutex every time thread A or thread B touch the my_list variable. Nothing unusual so far.

But then comes a third thread, thread C. This thread will never ever touch the linked list in any way, but it will need to know from time to time whether the list is empty or not. So, the only thing thread C will do is

if (my_list) {

    do_something_completely_unrelated();

}

Do I have to use a mutex for that? I believe it is an atomic operation, so no mutex is required. Is this correct?

EDIT

I will add here a bit of context. The reason why I would like to avoid using a mutex is that the list gets updated rarely (always), but the check coming from thread C happens every few milliseconds, so the less operations the better.

If the list appears to be non-NULL, then a proper check using a mutex is triggered by thread C, and if it is confirmed that the list is not empty thread C stops its obsessive check.

Upvotes: 4

Views: 1246

Answers (1)

klutt
klutt

Reputation: 31409

TL;DR

According to the standard, it is undefined behavior to read a variable when it's written if at least one of the operations is non-atomic.

Longer answer

From comment section, you seem to wonder if it will crash your program, or if the worst thing that may happen is that you get the wrong value. Your comment, emphasis mine:

Thank you. But concretely what could happen bad? Let's say the variable is NULL but is being changed right now by thread A to address xxxxxx. Thread C attempts to read it. What value can it get? Either NULL or xxxxxx, and both are fine. Am I wrong in assuming that the program will not crash?

I would say that this simple check will most likely not cause your program to crash. The check operation is safe in the sense that you will most likely get a value. The value may be wrong, but the check alone will most likely not crash your program.

However, it IS undefined behavior:

The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.

C18 Standard, section 5.1.2.4, paragraph 35

Then you posted this follow up comment:

This is actually not so important, but am I correct in assuming that if thread A is changing the value from NULL to xxxxxx (or vice versa) I will definitely not get yyyyyy, but either NULL or xxxxxx?

Here I'd say your assumption is wrong. AFIK, there's nothing in the standard that says that a pointer assignment needs to be an atomic operation, and I would be surprised if it was. And as I mentioned above, it IS undefined behavior.

Suggested solutions

Use _Atomic keyword

Declare the list with the _Atomic qualifier. It has some limitations. For instance:

  1. It's not a mandatory feature, so it might reduce portability

  2. It cannot be used with arrays

  3. If used with a struct, the fields of the struct cannot be accessed individually

2 and 3 should not matter to you, since the list is just a pointer.

Read about _Atomic here: https://en.cppreference.com/w/c/language/atomic

Use a copy that doesn't get updated on each access

If _Atomic is not an option, here is a solution in pseudo code:

if ( now() - lastUpdated > ms ) // If it was more than ms milliseconds since last update  
    lock(myMutex)
    myListCopy = myList
    unlock(myMutex)
    lastUpdated = now()

if(myListCopy) 
    do_something_completely_unrelated();

lastUpdated and myListCopy are preferably variables that are local to the function, but the important part is that thread A and B never touches them.

Upvotes: 5

Related Questions