Deadlock.

I recently made code that causes a deadlock (or atleast tries to make it).

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <thread>
#include <exception>
using namespace std;

bool doNot = 1; // this bool will prevent func1 and func2 from doing their tasks
thread* fn1; // pointer to t1 thread (defined in main function)
thread* fn2; // pointer to t2 thread (defined in main function)
void func1(bool x)
{
	while(doNot) {;} // waiting for changing doNot to false (doing it in main function)
	::fn2->join(); // trying to cause deadlock
}

void func2(bool x)
{
	while(doNot) {;} // waiting for changing doNot to false (doing it in main function)
	::fn1->join(); // trying to cause deadlock
}


int main()
{
	// making threads for func1 and func2. I don't know why I've added arguments to func1 & func2
	thread t1(func1, 1); 
	thread t2(func2, 1);
	// assigning values to pointers
	::fn1 = &t1;
	::fn2 = &t2;
	::doNot = 0; // STARTING!
	t1.join();
	t2.join();
	cout << "Hello!"; // This code will never be done...
}

The output is:
1
2
terminate called after throwing an instance of 'std::system_error'
  what():  Resource deadlock avoided


(That code had do make a deadlock (or try to make it))
What the code does?
It makes 2 threads for 2 functions, and 2 pointers to these threads. Pointers are defined then, so we can start by setting doNot to false.
And then... deadlock!
What is deadlock? So the deadlock is 2 processes waiting for each other. So we made these pointers. func1 and func2 are using these pointers. You can see, the func1 (its thread: t1, pointer to t1: fn1) is waiting for func2 (its thread: t2, pointer to t2: fn2) using fn2 pointer and vice versa. So that's the deadlock.

1
2
3
4
5
6
7
8
9
10
void func1(bool x)
{
	while(::doNot) {;} // waiting...
	fn2->join(); // now (thread of) func1 waiting for (thread of) func2
}
void func2(bool x)
{
	while(::doNot) {;} // waiting...
	fn1->join(); // now (thread of) func2 waiting for (thread of) func1
}


That's all! Try to avoid these deadlocks.
You can catch them, obviously.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ...

int main()
{
	// entire code of main() in 'try'
	try
	{
		thread t1(func1, 1); 
		thread t2(func2, 1);
		::fn1 = &t1;
		::fn2 = &t2;
		::doNot = 0;
		t1.join();
		t2.join();
		cout << "Hello!";
	}
	catch(exception& e) // catching it. You can type 'std::system_error& e', according to the code's output
	{
		e.what();
		// ...
	}
}

I hope you enjoyed this topic;
return 0;
}
There are problems with the code apart from the intentional deadlock.

And catching an exception in one of the threads is not really solving the problem, but is side-stepping it.
Last edited on
Yes. As you can see in code's output, it stops code executing [terminate called after throwing (...)]
main thread writes to doNot and the two other threads read from doNot without synchronization; the behavior is undefined
Topic archived. No new replies allowed.