Preventing deadlock in two thread program - java

Suppose I have the following code, where one thread generates squares and writes them to a buffer while another thread prints them:
import java.util.*;
public class Something {
public static Buffer buffer = new Buffer();
public static class Buffer {
private int[] buffer;
private static final int size = 10;
//Indexes for putting and taking element form buffer
private int in, out;
//Number of elements in buffer
private int k;
public Buffer() {
buffer = new int[size];
in = 0;
out = 0;
k = 0;
}
public synchronized void put(int e) {
try {
while (k == buffer.length) {
wait();
}
} catch (InterruptedException ex) {
}
buffer[in] = e;
k++;
in = ++in % size;
notifyAll();
}
public synchronized int take() {
try {
while (k == 0) {
wait();
}
} catch (InterruptedException ex) {
}
int e = buffer[out];
buffer[out] = 0;
out = ++out % size;
k--;
notifyAll();
return e;
}
public synchronized boolean notEmpty() {
return k != 0;
}
}
public static class Generator implements Runnable {
int limit;
public Generator(int lim) {
limit= lim;
}
#Override
public void run() {
for (int i = 1; i < limit; i++) {
buffer.put(i * i);
}
}
}
public static class Printer implements Runnable {
private Thread[] generators;
public Printer(Thread[] gen) {
generators = gen;
}
public synchronized boolean nobody() {
for (Thread th : generators) {
if (th.isAlive()) {
return false;
}
}
return true;
}
#Override
public void run() {
int x = 0;
while (!nobody() || buffer.notEmpty()) {
x = buffer.take();
System.out.println(x);
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread generator = new Thread(new Generator(69));
Thread printer = new Thread(new Printer(new Thread[]{generator}));
generator.start();
printer.start();
generator.join();
printer.join();
}
}
Generator should generate squares of numbers until it reaches some limit (limit = 69, in this case). Printer should print all values generated by Generator. Buffer works somewhat like ring buffer. Indexes for putting (in) and taking (out) element are cycling in bounds of buffer size. Buffer has methods for putting and taking elements from buffer. Generator thread cannot put elements in buffer if it is full (that is, there are no zero elements; zero element is 0, for precision sake...). Printer works this way: first it checks if there are any alive generator threads and then checks if buffer contains only zero elements. If neither of these conditions is true, printer thread terminates.
Now, to the problem. I always get printed all squares from 1 to 68, which is expected output of this program. However, on very rare occasion after all numbers had been output I get a deadlock. How rarely? Well, maybe in 1 out of 100 executions of program. I had to keep hitting "F6" on NetBeans like crazy to get a deadlock. And yes, I know that I can test this simply putting all main code in for loop.
Conversely, if I comment out print line in Printers' run method, deadlock happens almost all the time. Here:
#Override
public void run() {
int x = 0;
while (!nobody() || buffer.notEmpty()) {
x = buffer.take();
//System.out.println(x);
}
}
I do not expect this behavior, because element still gets taken from buffer and generator should be awoken.
Why does this happen? And how do I fix it?
Sorry if question isn't clear enough, I'll try to clarify it as best I can if needed.

I think I fount the problem. Here is what I got: There is a very short moment in time, where the Generator thread is still alive (i.e. Thread.isAlive() will return true), but the Generator has left the for-loop within run(). If the Printer queries its while-condition within its run() at this point in time, it will try to take() something, that is not there (and never will be). Indeed, you can verify, that the Generator always finishes, meaning termination detection on the side of the Printer is faulty. For a hot fix, you can simply add a magic constant is Printers while condition:
#Override
public void run() {
int x = 0;
int count = 0;
while (++count < 69) {
x = buffer.take();
System.out.println(x);
}
}
For a clean termination detection, you could set some common flag-variable to false, signaling that the Generator has finished work and the Printer can stop working. But this has to be done in a synchronized manner, meaning the Printer is not allowed to query this condition, while the Generator is after its last push, but before it sets this common flag.

Related

Program with race conditions in Windows, but not in Ubuntu

In an assignment designed to highlight race conditions, we were given the following code
public class IncreaseDecrease {
public static int IntegerVariable = 0;
public static final int NUM_ITER = 5000000;
public static void main(String[] args) throws Exception {
Increase inc;
Decrease dec;
while (true) {
inc = new Increase();
dec = new Decrease();
inc.start();
dec.start();
inc.join();
dec.join();
System.out.println(IntegerVariable);
IntegerVariable = 0;
Thread.sleep(750);
}
}
}
class Increase extends Thread {
#Override
public void run() {
for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) {
IncreaseDecrease.IntegerVariable++;
}
}
}
class Decrease extends Thread {
#Override
public void run() {
for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) {
IncreaseDecrease.IntegerVariable--;
}
}
}
this code which would be expected to print 0 if each thread can update the value before the other one reads it, but that does not happen due to race conditions, it can print any value between -5000000 and 5000000.
I ran that code on windows and repl.it, and it gave the expected output:
-310951
-1918567
-3374495
-3219135
-2286639
-3221055
-3794319
-2442047
-2776415
-3617391
But on Ubuntu, when I ran it, it gave 0 every time.
My question is, why does this happen? Does Ubuntu manage threads differently, or is it just a special case for my computer?
Edit:
After putting the increment in a different method and adding one more operation to it, I observed the race condition. Here's the final code:
public class IncreaseDecrease {
public static int IntegerVariable = 0;
public static final int NUM_ITER = 5000000;
public static void main(String[] args) throws Exception {
Increase inc;
Decrease dec;
while (true) {
inc = new Increase();
dec = new Decrease();
inc.start();
dec.start();
inc.join();
dec.join();
System.out.println(IntegerVariable);
IntegerVariable = 0;
Thread.sleep(750);
}
}
public static void increment ()
{
IntegerVariable++;
double a = Math.pow(3, 7);
}
public static void decrement()
{
IntegerVariable--;
double a = Math.pow(3, 7);
}
}
class Increase extends Thread {
#Override
public void run() {
for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) {
IncreaseDecrease.increment();
}
}
}
class Decrease extends Thread {
#Override
public void run() {
for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) {
IncreaseDecrease.decrement();
}
}
}
I'd go out on a limb and claim that Hotspot under Linux using the server compiler while it doesn't on Windows is the more likely explanation: The compiler can replace the whole loop with a single expression which is something that HotSpot is definitely capable of. Adding any native method will make that impossible thereby making it much more likely to observe the race condition
I would guess that this might be the case as well.
Have you tried making your IntegerVariable volatile? This would prevent some compiler optimization that might occur.
public static volatile int IntegerVariable = 0;
There is a common misconception about threads in Java that they truly and efficiently interleave processing evenly. That is actually not quite true and different JVMs on different systems work differently.
It all arises from when the JVM decides to switch threads. A JVM will probably switch threads whenever it hits a Thread.sleep() or a blocking method such as as synchronized or a lock but generally if a thread is not doing anything that involves blocking etc it will let the thread run.
Your loops ar spinning on incrementing and decrementing a value with no pause. If you add a Thread.sleep(0) call in your loops you will probably see a difference because you are offering the JVM many more opportunities to switch your thread out/in.
for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) {
IncreaseDecrease.IntegerVariable--;
// Add this.
Thread.sleep(0);
}

Thread.sleep blocks other Thread

I have a Output class which just prints everything that it gets to print.
public class Output {
private static List<String> textList = new ArrayList<>();
private static Output output = null;
private Output() {
Runnable task = () -> {
int lastIndex = 0;
while (true) {
while (lastIndex < textList.size()) {
System.out.println(lastIndex + " - " + textList.size() + ": " + textList.get(lastIndex));
outputText(textList.get(lastIndex));
lastIndex ++;
}
}
};
new Thread(task).start();
}
private static void outputText(String text) {
synchronized (System.out) {
System.out.println(text);
}
}
public static void say(String text) {
if (output == null) {
output = new Output();
}
textList.add(text);
}
}
When I add something to print, everything works fine:
for (int i = 0; i < 10; i++) {
Output.say("" + i);
}
But when I add a Thread.sleep to the loop it stops on the first output:
for (int i = 0; i < 10; i++) {
Output.say("" + i);
Thread.sleep(100);
}
How can I prevent it? I mean, I'm stopping with sleep just the main thread and not the separate thread.
When you don’t synchronize threads correctly, there is no guaranty that threads see updates made by other threads. They may either completely miss updates or see only parts of them, creating an entirely inconsistent result. Sometimes they may even appear to do the right thing. Without proper synchronization (in the sense of any valid construct specified to be thread safe), this is entirely unpredictable.
Sometimes, the chances of seeing a particular behavior are higher, like in your example. In most runs, the loop without sleep will complete before the other thread even starts its work, whereas inserting sleep raises the chance of lost updates after the second thread has seen values. Once the second thread has seen a value for textList.size(), it might reuse the value forever, evaluating lastIndex < textList.size() to false and executing the equivalent of while(true) { }.
It’s funny that the only place where you inserted a construct for thread safety, is the method outputText that is called by a single thread only (and printing to System.out is synchronized internally in most environments anyway).
Besides, it’s not clear why you are creating an object of type Output that has no relevance here, as all fields and methods are static.
Your code can be corrected and simplified to
public static void main(String[] args) throws InterruptedException {
List<String> textList = new ArrayList<>();
new Thread( () -> {
int index=0;
while(true) synchronized(textList) {
for(; index<textList.size(); index++)
System.out.println(textList.get(index));
}
}).start();
for (int i = 0; i < 10; i++) {
synchronized(textList) {
textList.add(""+i);
}
Thread.sleep(100);
}
}
though it still contains the issues of you original code of never terminating due to the infinite second thread and also burning the CPU with a polling loop. You should let the second thread wait for new items and add a termination condition:
public static void main(String[] args) throws InterruptedException {
List<String> textList = new ArrayList<>();
new Thread( () -> {
synchronized(textList) {
for(int index=0; ; index++) {
while(index>=textList.size()) try {
textList.wait();
} catch(InterruptedException ex) { return; }
final String item = textList.get(index);
if(item==null) break;
System.out.println(item);
}
}
}).start();
for (int i = 0; i < 10; i++) {
synchronized(textList) {
textList.add(""+i);
textList.notify();
}
Thread.sleep(100);
}
synchronized(textList) {
textList.add(null);
textList.notify();
}
}
This is still only an academic example that you shouldn’t use in real life code. There are classes for thread safe data exchange provided by the Java API removing the burden of implementing such things yourself.
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
String endMarker = "END-OF-QUEUE"; // the queue does not allow null
new Thread( () -> {
for(;;) try {
String item = queue.take();
if(item == endMarker) break;// don't use == for ordinary strings
System.out.println(item);
} catch(InterruptedException ex) { return; }
}).start();
for (int i = 0; i < 10; i++) {
queue.put(""+i);
Thread.sleep(100);
}
queue.put(endMarker);
}

JVM seems to stop context switching very quickly

I'm implementing the naive version of the Producer-Consumer concurrency problem. And it the threads are switched between at first very quickly but then stop around i = 50. Adding additional print statements for some reason allows the JVM to context switch the threads and complete the program.
Why doesn't the JVM context switch the threads so that the program will complete?
// Producer - Consumer problem
// Producer constantly puts items into array, while consumer takes them out
class IntBuffer {
private int[] buffer;
private int index;
public IntBuffer(int size) {
buffer = new int[size];
index = 0;
}
public void add(int item) {
while (true) {
if (index < buffer.length) {
buffer[index] = item;
index++;
return;
}
}
}
public int remove() {
while (true) {
if (index > 0) {
index--;
int tmp = buffer[index];
buffer[index] = 0;
return tmp;
}
}
}
public void printState() {
System.out.println("Index " + index);
System.out.println("State " + this);
}
public String toString() {
String res = "";
for (int i = 0; i < buffer.length; i++) {
res += buffer[i] + " ";
}
return res;
}
}
class Producer extends Thread {
private IntBuffer buffer;
public Producer(IntBuffer buffer) {
this.buffer = buffer;
}
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("added " + i);
buffer.add(i);
}
}
}
class Consumer extends Thread {
private IntBuffer buffer;
public Consumer(IntBuffer buffer) {
this.buffer = buffer;
}
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("removed " + i);
buffer.remove();
}
}
}
public class Main {
public static void main(String[] args) {
IntBuffer buf = new IntBuffer(10);
Thread t1 = new Thread(new Producer(buf));
Thread t2 = new Thread(new Consumer(buf));
t1.start();
t2.start();
System.out.println(buf);
}
}
Your question does not provide enough details to give an answer with a confidence(at least, it is not clear where those additional print statements go), so I'll make some(reasonable) guesses here.
Your code is not correct. IntBuffer is not thread-safe, but it is accessed from multiple threads.
Any operations on the IntBuffer do not establish a happens-before relationship, so the changes made by one thread may be not visible for another thread. That's why the Producer thread can "believe" that the buffer is full while the Consumer thread "believes" that it is empty. In this case the program never terminates.
This two statements are not guesses, they are facts based on the Java memory model. And here goes my guess why the additional print statements sorta fix it:
In many JVM implementations, the println methods uses syncronization internally. That's why a call to it creates a memory fence and makes changes made in one thread visible to the other one, eliminating the issue described in 2).
However, if you really want to solve this problem, you should make the IntBuffer thread-safe.
At the minimum you need the volatile keyword on both the buffer and index. Second, you need to access index only once under the true arm of the ifs you have there. Even after that, you will face out of bounds access at 10, you will need more fixing to work around that. Your buffer is de facto stack. So, even after all of this, your remove() can be working with stale index, thus you will be removing in the middle of the stack. You could use 0 as special value marking the slot already handled end empty.
With all of this, I do not think your code is easily salvageable. It pretty much needs complete rewrite using proper facilities. I agree with #kraskevich:
#StuartHa Naive usually means simple(and most likely inefficent) solution, not an incorrect one.

Is my code in a state of deadlock?

On compiling my code below it seems to be in a state of deadlock, and i don't know how i can fix it. I am attempting to write a pipeline as a sequence of threads linked together as a buffer, and each thread can read the preceding node in the pipeline, and consequentially write to the next one. The overall goal is to spilt a randomly generated arraylist of data over 10 threads and sort it.
class Buffer{
// x is the current node
private int x;
private boolean item;
private Lock lock = new ReentrantLock();
private Condition full = lock.newCondition();
private Condition empty = lock.newCondition();
public Buffer(){item = false;}
public int read(){
lock.lock();
try{
while(!item)
try{full.await();}
catch(InterruptedException e){}
item = false;
empty.signal();
return x;
}finally{lock.unlock();}
}
public void write(int k){
lock.lock();
try{
while(item)
try{empty.await();}
catch(InterruptedException e){}
x = k; item = true;
full.signal();
}finally{lock.unlock();}
}
}
class Pipeline extends Thread {
private Buffer b;
//private Sorted s;
private ArrayList<Integer> pipe; // array pipeline
private int ub; // upper bounds
private int lb; // lower bounds
public Pipeline(Buffer bf, ArrayList<Integer> p, int u, int l) {
pipe = p;ub = u;lb = l;b = bf;//s = ss;
}
public void run() {
while(lb < ub) {
if(b.read() > pipe.get(lb+1)) {
b.write(pipe.get(lb+1));
}
lb++;
}
if(lb == ub) {
// store sorted array segment
Collections.sort(pipe);
new Sorted(pipe, this.lb, this.ub);
}
}
}
class Sorted {
private volatile ArrayList<Integer> shared;
private int ub;
private int lb;
public Sorted(ArrayList<Integer> s, int u, int l) {
ub = u;lb = l;shared = s;
// merge data to array from given bounds
}
}
class Test1 {
public static void main(String[] args) {
int N = 1000000;
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i=0;i<N;i++) {
int k = (int)(Math.random()*N);
list.add(k);
}
// write to buffer
Buffer b = new Buffer();
b.write(list.get(0));
//Sorted s = new Sorted();
int maxBuffer = 10;
int index[] = new int[maxBuffer+1];
Thread workers[] = new Pipeline[maxBuffer];
// Distribute data evenly over threads
for(int i=0;i<maxBuffer;i++)
index[i] = (i*N) / maxBuffer;
for(int i=0;i<maxBuffer;i++) {
// create instacen of pipeline
workers[i] = new Pipeline(b,list,index[i],index[i+1]);
workers[i].start();
}
// join threads
try {
for(int i=0;i<maxBuffer;i++) {
workers[i].join();
}
} catch(InterruptedException e) {}
boolean sorted = true;
System.out.println();
for(int i=0;i<list.size()-1;i++) {
if(list.get(i) > list.get(i+1)) {
sorted = false;
}
}
System.out.println(sorted);
}
}
When you start the run methods, all threads will block until the first thread hits full.await(). then one after the other, all threads will end up hitting full.await(). they will wait for this signal.
However the only place where full.signal occurs is after one of the read methods finishes.
As this code is never reached (because the signal is never fired) you end up with all threads waiting.
in short, only after 1 read finishes, will the writes trigger.
if you reverse the logic, you start empty, you write to the buffer (with signal, etc, etc) and then the threads try to read, I expect it will work.
generally speaking you want to write to a pipeline before reading from it. (or there's nothing to read).
I hope i'm not misreading your code but that's what I see on first scan.
Your Buffer class it flipping between read and write mode. Each read must be followed by a write, that by a read and so on.
You write the buffer initially in your main method.
Now one of your threads reaches if(b.read() > pipe.get(lb+1)) { in Pipeline#run. If that condition evaluates to false, then nothing gets written. And since every other thread must still be the very same if(b.read(), you end up with all reading threads that can't progress. You will either have to write in the else branch or allow multiple reads.

Semaphores: Critical Section with priorities

I'm writing a program in Java that deals with Semaphores for an assignment. I'm still new to the idea of Semaphores and concurrency.
The description of the problem is as follows:
A vector V[] of booleans. V[i] is "True"if Pi needs to use the critical section.
A vector of binary semaphores B[] to block processes from entering their critical section: B[i] will be the semaphore blocking process Pi.
A special scheduler process SCHED is used whenever a blocked process needs to be awakened to use the critical section.
SCHED is blocked by waiting on a special semaphore S
When a process Pi needs to enter the critical section, it sets V[i] to "True", signals the semaphore S and then waits on the semaphore B[i].
Whenever SCHED is unblocked, it selects the process Pi with the smallest index i for which V[i] is "True". Process Pi is then awakened by signaling B[i] and SCHED goes back to sleep by blocking on semaphore S.
When a process Pi leaves the critical section, it signals S.
This is my code:
import java.util.concurrent.Semaphore;
public class Process extends Thread {
static boolean V[];
int i;
static Semaphore B[]; //blocking semaphore
static Semaphore S;
private static int id;
static int N;
static int insist = 0;
public static void process (int i, int n) {
id = i;
N = n;
V = new boolean[N];
}
private void delay () {
try {
sleep (random(500));
}
catch (InterruptedException p) {
}
}
private static int random(int n) {
return (int) Math.round(n * Math.random() - 0.5);
}
private void entryprotocol(int i) {
V[Process.id] = true;
int turn = N;
while (V[Process.id] == true && turn == N) {
System.out.println("P" + Process.id + " is requesting critical section");
signal(S);
}
critical(Process.id);
wait(B[Process.id]);
V[Process.id] = false;
}
private void wait(Semaphore S) {
if (Process.id > 0) {
Process.id--;
} else {
//add Process.id to id.queue and block
wait(B[Process.id]);
}
}
private void signal(Semaphore S) {
if (B[Process.id] != null) {
Sched(Process.id);
} else {
Process.id++; //remove process from queue
critical(Process.id); //wakes up current process
}
}
private void critical(int i) {
System.out.println("P" + Process.id + " is in the critical section");
delay();
exitprotocol(i);
}
private void exitprotocol(int i) {
System.out.println("P" + Process.id + " is leaving the critical section");
V[id] = false;
signal(S);
}
public void Sched(int i) {
if (B[Process.id] == null) {
signal(B[Process.id]);
}
wait(S);
}
public void run() {
for (int i = 0; i < 5; i++) {
Sched(i);
entryprotocol(Process.id);
try {
wait(Process.id);
}
catch (InterruptedException p) {
}
signal(S);
}
}
public static void main (String[] args) {
int N = 5;
Process p[] = new Process[N];
for (int i = 0; i < N; i++) {
p[i] = new Process();
p[i].start();
}
}
}
I believe my logic here is correct but I'm getting a lot of errors (such as Exception in thread "Thread-1" java.lang.NullPointerException). Can any shed some light on what I'm doing wrong & provide me with some help. It's greatly appreciated!
Your NPE is probably due to the fact that you never initialize your Semaphore array - but its hard to say without a proper stack trace.
Two pieces of advice:
1) You might want to give your class variables more meaningful names than :
B
N
S
V.
Imagine walking away from this project and revisiting it in 4 months and had to read through that.
2) Figure out your class model on on a white board before writing any code. You have methods that take semaphores with the same name as some of your static fields. What are the relationships of the objects in your program? If you don't know, odds are your program doesn't know either.

Categories

Resources