thread1 finish before thread2

Hi there, I want the producer thread finish before the consumer thread gets executed. How can I do that?

the output looks like this:
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
buffer 1 has value of 1
buffer 1 has value of 2
buffer 1 has value of 3
buffer 1 has value of 4
buffer 1 has value of 5
buffer 1 has value of 6
buffer 1 cleared.buffer 1 has value of 7
buffer 2 has value of 1
buffer 2 has value of 2
buffer 2 has value of 3
buffer 2 has value of 4
buffer 2 has value of 5
buffer 2 has value of 6
buffer 2 has value of 7
buffer 3 has value of 1
buffer 3 has value of 2
buffer 3 has value of 3

buffer 3 has value of 4
buffer 3 has value of 5
buffer 3 has value of buffer 2 cleared.6

buffer 3 has value of 7
buffer 4 has value of 1
buffer 4 has value of 2
buffer 4 has value of 3
buffer 4 has value of 4
buffer 4 has value of 5
buffer 4 has value of 6
buffer 4 has value of 7
buffer 5 has value of 1
buffer 5 has value of 2
buffer 5 has value of 3
buffer 5 has value of 4
buffer 3 cleared.buffer 5 has value of 5
buffer 5 has value of 6

buffer 5 has value of 7
buffer 6 has value of 1
buffer 6 has value of 2
buffer 6 has value of 3
buffer 6 has value of 4
buffer 6 has value of 5
buffer 6 has value of 6
buffer 6 has value of 7
buffer 7 has value of 1
buffer 7 has value of 2
buffer 7 has value of 3
buffer 4 cleared.buffer 7 has value of 
4buffer 5 cleared.

buffer 6 cleared.
buffer 7 has value of 5
buffer 7 has value of 6
buffer 7 has value of 7
buffer 7 cleared.


However, I want to clear buffers ONLY after I finish producing numbers into them.

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include <thread>
#include <vector>

using namespace std;

int BUFFER_SIZE = 7;

vector<int> buffer1(BUFFER_SIZE);
vector<int> buffer2(BUFFER_SIZE);
vector<int> buffer3(BUFFER_SIZE);
vector<int> buffer4(BUFFER_SIZE);
vector<int> buffer5(BUFFER_SIZE);
vector<int> buffer6(BUFFER_SIZE);
vector<int> buffer7(BUFFER_SIZE);

void producer()
{
	//fill these buffers with numbers 0, 1, ..., 7
	for (int i = 1; i < BUFFER_SIZE+1; i++)
	{
		buffer1.push_back(i);
		cout << "buffer 1 has value of " << i << endl;
	}

	for (int i = 1; i < BUFFER_SIZE + 1; i++)
	{
		buffer1.push_back(i);
		cout << "buffer 2 has value of " << i << endl;
	}

	for (int i = 1; i < BUFFER_SIZE + 1; i++)
	{
		buffer1.push_back(i);
		cout << "buffer 3 has value of " << i << endl;
	}

	for (int i = 1; i < BUFFER_SIZE + 1; i++)
	{
		buffer1.push_back(i);
		cout << "buffer 4 has value of " << i << endl;
	}

	for (int i = 1; i < BUFFER_SIZE + 1; i++)
	{
		buffer1.push_back(i);
		cout << "buffer 5 has value of " << i << endl;
	}

	for (int i = 1; i < BUFFER_SIZE + 1; i++)
	{
		buffer1.push_back(i);
		cout << "buffer 6 has value of " << i << endl;
	}

	for (int i = 1; i < BUFFER_SIZE + 1; i++)
	{
		buffer1.push_back(i);
		cout << "buffer 7 has value of " << i << endl;
	}
}

void consumer()
{
	buffer1.clear();
	cout << "buffer 1 cleared." << endl;
	buffer2.clear();
	cout << "buffer 2 cleared." << endl;
	buffer3.clear();
	cout << "buffer 3 cleared." << endl;
	buffer4.clear();
	cout << "buffer 4 cleared." << endl;
	buffer5.clear();
	cout << "buffer 5 cleared." << endl;
	buffer6.clear();
	cout << "buffer 6 cleared." << endl;
	buffer7.clear();
	cout << "buffer 7 cleared." << endl;
}

int main()
{
	thread producerThread(producer);
	thread consumerThread(consumer);

	producerThread.join();
	consumerThread.join();

	system("PAUSE");
	return 0;
}
Last edited on
I suggest
 
const int buffer_size = 7;


why do you have buffer2, buffer3, buffer4, etc
you are not using them...
Last edited on
You could do this in three ways I reckon, there are possibly (certainly?) several others:
(a) since the producer thread has to finish before the consumer thread gets executed just eschew all concurrency and call the functions asynchronously in which case your main() would look something like ... :
1
2
3
4
5
int main()
{
   producer();
   consumer();
}


... but this is probably not what you had in mind and/or would like to hear, learn.

So let's look at a couple of other approches that does use concurrency. In both cases the consumer() thread has to wait for the producer thread to complete before it can proceed. The two ways of doing this are:
(b) using an ordinary bool with std::condition_variable: the producer() thread wakes up the consumer() thread through the condition variable:
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
35
36
37
38
39

# include <iostream>
# include <mutex>
# include <future>
# include <condition_variable>

bool boolReady;
std::mutex mutexReady;
std::condition_variable cond_varReady;

void producer()
{ 
    //do whatever consumer() needs as prep
    //signal that producer() is done
    {
       std::lock_guard<std::mutex> lg(mutexReady);
       boolReady = true;
    }//release lock
    cond_varReady.notify_one();//notify_all() to notify multiple waiting threads
}

void consumer()
{
    //wait until producer() is done i.e boolReady == true
    {
       std::unique_lock<std::mutex> ul(mutexReady);
       //need unique_lock, lock_guard is not enough because consumer() might lock and unlock the mutex
       cond_varReady.wait(ul, [] { return boolReady; });
       //to guard against spurious wakeups query the status of boolReady
    } // release lock
    // do whatever happens after producer() is done 
}

int main()
{
    auto f1 = std::async(std::launch::async, producer);
    auto f2 = std::async(std::launch::async, consumer);
    //could also use thread based, instead of task-based, approach as in the OP 
}


(c) use an std::atomic<bool> instead of the ordinary bool in (a) in which case no mutex is required. The reasons the mutex is required in (b) are that: [/quote]
(i) In general, reading the writing even for fundmenatal data types is not atomic. Thus you might have a half-written Boolean, ...
(ii) The generated code might change the order of operations, so the providing thread might set the ready flag before the data is provided [/quote] - "The C++ Standard Library" (2nd ed), N Josuttis though the second reason might be addressed by C++17 I think
In any case the mutex solves both problems but might be expensive in terms of resources and it might be worth using atomics instead - the standard guarantees sequential consistency i.e. in a thread atomic operations are guaranteed to happen in the order as programmed. Now the program outline might look as follows:
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
# include <iostream>
# include <atomic>
# include <future>
# include <thread>
# include <chrono>

std::atomic<bool> boolReady{false};
//always initialize atomic objects because the default ctor does not fully initialize

void producer()
{ 
    //do whatever consumer() needs as prep
   
    boolReady.store(true);
    // store() assigns a new value     
}

void consumer()
{ 
    while(!boolReady.load())
    //load() returns current value 
    {
      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
    // do whatever happens after producer() is done
}

int main()
{
   //same as case (b)
}
the simple approach is to wrap your thread creation and execution in a class with a counter and a done variable. A method invokes the threads, and has a waiter loop (while counter < num_threads sleep(1); ) All the threads increment the counter right before exit/completion, a static class member with a static function that anyone can call. After the waiter loop, a bool is set true, again this can be static with a static accessor.

Which is the object oriented way of saying you can make a global counter, each thread increments it, and when the total = the number of threads, they all finished.

There are many ways, and you can poke in a lot of features, but that is the bare bones of it. If a waiter loop isn't good (eating cpu that should be processing) you can avoid that with a bit of workaround.




Last edited on
Topic archived. No new replies allowed.