Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ensure the comparison result still hold in multi-threading?

Suppose there are 3 threads,

Thread 1 and 2 will increase or decrease a global variable X atomically.

thread 1:

atomic_increase(X)

thread 2:

atomic_decrease(X)

Thread 3 will check if the X is greater than some predefined value and do things accordingly.

thread 3:

if( X > 5 ) {... logic 1 ...}
else {... logic 2 ....}

I think the atomic_xxx operations are not enough. They can only synchronize the modifications between thread 1 and 2.

What if X is changed by thread 1 or 2 after thread 3 finishes the comparison and enters logic 1.

Do I have to use a mutex to synchronize all the 3 threads when modifying or reading the X?

ADD 1

BTW, logic 1 and logic 2 don't modify the X.

like image 408
smwikipedia Avatar asked Dec 15 '21 09:12

smwikipedia


People also ask

How can we ensure that instance of this class can be safely used by multiple threads?

Using Volatile keyword A volatile keyword is a field modifier that ensures that the object can be used by multiple threads at the same time without having any problem. volatile is one good way of ensuring that the Java program is thread-safe.

How does one ensure thread Synchronisation such that all threads wait until all threads arrive?

Barriers. Barriers are a synchronization mechanism that can be used to coordinate multiple threads working in parallel. A barrier allows each thread to wait until all cooperating threads have reached the same point, and then continue executing from there.

What are some things to worry about in a multi threaded system?

Deadlocks, Starvation, Livelock and Race Conditions Deadlocks, starvation, and race conditions are the bane of multithreaded programming and they can bring down any system in which they occur.


2 Answers

In short yes, reads also need to be synchronized in some way, otherwise the risk of inconsistent reads is real. A read performed between the read and write of atomic_increase will be inconsistent.

However if logic 1 or logic 2 do stuff to X, your problems doesn't seem to stop right there. I think then you need the concept of a transaction, where it starts with a read (the X > 5 thing) and then ends with a write (logic 1 or logic 2).

like image 109
mlntdrv Avatar answered Oct 23 '22 04:10

mlntdrv


Yes, And the Answer is happens before link, Lets say Thread-1 started executing atomic_increase method. It will hold the lock and enter the synchronized block to update X.

private void atomic_increase() {
    synchronized (lock) {
        X = X + 1;  // <-- Thread-1 entered synchronized block, yet to update variable X
    }
}

Now, for Thread-3 to run the logic, it needs to read the variable X, and if it is not synchronized (on the same monitor), the variable X read can be an old value since it may not yet updated by Thread-1.

private void runLogic() {
    if (X > 5) { // <-- Reading X here, can be inconsistent no 
                   happens-before between atomic_increase and runLogic
    } else {

    }
}

We could have prevented this by maintaining a happens-before link between atomic operation and run_logic method. If the runLogic is synchronized (on the same monitor) , then it would have to wait until the variable X to be updated by the Thread-1. So we are guaranteed to get the last updated value of X

private void runLogic() {
    synchronized (lock) {
        if (X > 5) { // <-- Reading X here, will be consistent, since there 
                       is happens-before between atomic_increase and runLogic 
        } else {

        }
    }
}
like image 31
Turtle Avatar answered Oct 23 '22 05:10

Turtle