In this lab, we examine how multithreading can lead to the synchronization probl
ID: 3815729 • Letter: I
Question
In this lab, we examine how multithreading can lead to the synchronization problem known as race condition. We also examine how this problem can be solved using 2 constructs provided by the operating system: semaphores and monitors.
1. Race condition
A race condition occurs when two or more threads can access shared data and they try to change it concurrently. Because the kernel can swap between threads at any time, you don't know the order in which the threads will attempt to access the shared data.
In the following, we will create a class that stores a variable, global, initialized to 0.We also create two Thread classes that attempt to access the shared variable. IncrementingThread is a thread that increments global 90,000,000 times, while DecrementingThread concurrently decrements global the same number of times.
1. What is the expected value of global when both threads have finished executing?
A race condition occurs when two or more threads can access shared data and they try to change it concurrently. Because the kernel can swap between threads at any time, you don't know the order in which the threads will attempt to access the shared data.
In the following, we will create a class that stores a variable, global, initialized to 0.We also create two Thread classes that attempt to access the shared variable. IncrementingThread is a thread that increments global 90,000,000 times, while DecrementingThread concurrently decrements global the same number of times.
Open a terminal
Move to the labs directory that you created in lab 1:
student@Ubuntu:~$ cd ~/labs
Create a new directory called lab3:
student@Ubuntu:~/labs$ mkdir lab3
Move to lab3:
student@Ubuntu:~/labs$ cd lab3
Open an editor (vi or gedit) and create all 4 classes GlobalClass.java, IncrementingThread.java, DecrementingThread.java and RaceConditionDemo.java that are listed below. Save the classes into the lab3 directory.
Compile the classes:
student@Ubuntu:~/labs/lab3$ javac *.java
Run the RaceConditionDemo class several times:
student@Ubuntu:~ /labs/lab3 $ java RaceConditionDemo
What is the output of this program, most of the times? Is it what you expected?
public class GlobalClass {
private int global = 0;
public void incrementGlobal(){
global++;
}
public void decrementGlobal(){
global--;
}
public int getGlobal() {
return global;
}
}
public class IncrementingThread extends Thread {
private GlobalClass globalClass;
public IncrementingThread(GlobalClass globalClass) {
this.globalClass = globalClass;
}
public void run(){
for(int i = 0; i < 90000000; i++){
globalClass.incrementGlobal();
}
}
}
public class DecrementingThread extends Thread {
private GlobalClass globalClass;
public DecrementingThread(GlobalClass globalClass) {
this.globalClass = globalClass;
}
public void run(){
for(int i = 0; i < 90000000; i++){
globalClass.decrementGlobal();
}
}
}
public class RaceConditionDemo {
public static void main(String[] args) {
GlobalClass globalClass = new GlobalClass();
IncrementingThread it = new IncrementingThread(globalClass);
it.start();
DecrementingThread dt = new DecrementingThread(globalClass);
dt.start();
try {
it.join();
dt.join();
} catch( InterruptedException e){
System.out.println(e.getMessage());
}
System.out.println("Final global = " + globalClass.getGlobal());
}
}
public class GlobalClass {
private int global = 0;
public void incrementGlobal(){
global++;
}
public void decrementGlobal(){
global--;
}
public int getGlobal() {
return global;
}
}
Explanation / Answer
If we expect that we are having 2 threads here, so both should be given the processor to execute themselves for equal amount of time, the output value of 'global' variable should be 0.
But, this is the ideal thing, this never happens in actual CPU processing. You are running 2 threads, IncrementingThread and DecrementingThread.
And both of them are operating on the same data, int variable 'global'.
So, the final value depends on which thread got chance to execute for how much time.
Every time here you will get the different output.
For example, I executed this code in my terminal, and the outputs I got was every time the different numbers :
-85216120
-66827414
-75262593
73895139
-62992199
86205749
-56188793
83092
-83065380
-796727
-45941748
-75928168
These outputs will have the range [-90000000, 90000000].
If only the DecrementingThread gets chance to execute, -90000000 is printed.If only the IncrementingThread is getting chance to execute, 90000000 is printed. But this is not happening in real.
Both the threads will get the chance to execute, and the result will depend on which thread executed for how much time. If the IncrementingThread is executed for more time than the DecrementingThread, the result will be positive number. Otherwise the result will be the negative number if DecrementingThread gets more time to execute.
This is the examination you are supposed to carry out here.
This is the perfect example of Race Condition. And as mentioned in the first line, using monitor or semaphore can solve this issue of race condition.
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.