How to use mutex in loops properly in c++? - c++

I'm new for threads and mutex and ı trying to learn them. I write some code that generally create a queue that enqueue all of the numbers from the file ( this file has nearly 20.000 lines and lots of information) since this file contains a lots of information for procees ı need to have multithreads, at the beginning user create the number of threads, then ı stuck at the part that in a while loop ı wanted see which threads enter the loop for dequing the id from queue, but apparently just the first created thread enters and dequeue all of them, ı used mutex for ensure that while a thread enters the loop make it process (dequeue a number) then unlock this mutex in order to other threads can enter but apprently ı did a mistake . Here is the code `
void printer( DynIntQueue & myQueue) // takes the Dynamic Queue
{
//int count = 0;
queMutex.lock(); // lock it before any threads come it
while(!myQueue.isEmpty()) // check this condition
{
int num;
cout << "Thread " << this_thread::get_id << " is working" << endl; // this is for printing out which threads enter this loop
myQueue.dequeue(num); // deqeueu this number from queue
queMutex.unlock(); // unlock this in order to next thread might enter
queMutex.lock(); // when this thread enters lock it in order to other threads to wait
}
queMutex.unlock(); // if myQueue is empty since it is firsly locked, unlock this
}`
My output is like this: Thread 005C1659 is working Thread 005C1659 is working Thread 005C1659 is working Thread 005C1659 is working Thread 005C1659 is working Thread 005C1659 is working Thread 005C1659 is working Thread 005C1659 is working Thread 005C1659 is working Thread 005C1659 is working
This goes on until the myQueue is empty with the same thread. What can ı do ensure that other threads might enter this loop?
Edited: Here is the main part `
int main()
{
DynIntQueue firstQueue;
ifstream input;
string line;
int numofthreads;
input.open("data.tsv");
getline(input, line); // for first empty
int id, houseAge, avgRooms, avgBedRooms, latitue, longitute, medianPrice;
cout << "Please enter the number of threads you want " << endl;
cin >> numofthreads;
vector <thread> Threads(numofthreads);
while (!input.eof())
{
getline(input, line);
istringstream divider(line);
divider >> id >> houseAge >> avgRooms >> avgBedRooms >> latitue >> longitute >> medianPrice;
firstQueue.enqueue(id);
}
for (int i = 0; i < numofthreads; i++)
{
Threads[i] = thread(&printer, ref(firstQueue));
}
for (int i = 0; i < numofthreads; i++)
{
Threads[i].join();
}
return 0;
}

Note: std::this_thread::get_id() is a function, so you should be calling it. I assume this is just a copy/paste error.
If I add some work between opening and closing the queue, i clearly see two threads using the queue.
I don't think you have any issue with the code shown.
#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
struct DynIntQueue {
bool isEmpty() const { return q_.empty(); }
void dequeue(int &elem) { elem = q_.front(); q_.pop(); }
std::queue<int> q_{{10, 20, 4, 8, 92}};
};
std::mutex queMutex;
void printer( DynIntQueue & myQueue) {
queMutex.lock();
while(!myQueue.isEmpty()) {
int num;
std::cout << "Thread " << std::this_thread::get_id() << " is working" << std::endl;
myQueue.dequeue(num);
queMutex.unlock();
std::cout << "working outside the lock" << std::endl;
std::cout << "working outside the lock" << std::endl;
std::cout << "working outside the lock" << std::endl;
std::cout << "working outside the lock" << std::endl;
std::cout << "working outside the lock" << std::endl;
queMutex.lock();
}
queMutex.unlock();
}
int main() {
std::cout << "Hello World!\n";
DynIntQueue q;
std::thread t1([&q]() { printer(q); });
std::thread t2([&q]() { printer(q); });
t1.join();
t2.join();
}
$ clang++-7 -pthread -std=c++17 -o main main.c
$ ./main
Hello World!
Thread 139686844172032 is working
working outside the lock
working outside the lock
working outside the lock
working outside the lock
working outside the lock
Thread 139686835779328 is working
working outside the lock
working outside the lock
working outside the lock
working outside the lock
working outside the lock
Thread 139686844172032 is working
working outside the lock
working outside the lock
working outside the lock
working outside the lock
working outside the lock
Thread 139686835779328 is working
working outside the lock
working outside the lock
working outside the lock
working outside the lock
working outside the lock
Thread 139686844172032 is working
working outside the lock
working outside the lock
working outside the lock
working outside the lock
working outside the lock

Related

Destroy/replace thread on timer or command outside from the main thread

Currently I'm working on server development for an online game and decided to implement it as multithreaded application.
I have a main thread which implements while loop which abstractly gets data from the socket.
std::vector<std::thread> games_threads;
int start(int game_id) {
std::this_thread::sleep_for(std::chrono::seconds(10));
return end(game_id);
}
int end(int game_id) {
// some other conditions for turn end
return start(game_id);
}
int main() {
// socket implmementation
while(1) {
Message msg = socket.get_data();
switch(msg->action) {
case GAME_START:
std::thread game_thread(start, create_game());
game_thread.detach();
games_threads.push_back(game_thread);
break;
case TURN_END:
std::thread game_thread(end, msg->get_game());
game_thread.detach();
games_threads.push_back(game_thread);
break;
}
}
}
Game creates with turn start() method. And then after waiting 10 secs in call end() method which implements turn end.
After than turn end() method calls start().
But I need also implement force turn end method so I have race condition with 2 cases:
Start -> End normal workflow with 10s timeout (which makes game
thread unavailable for 10 secs)
Forced turn end command (TURN_END).
So I need somehow end the current game thread and replace with one user thread. Or just catch signals somehow with conditional variable but I have already freeze for 10sec and as far as I know I can't wait both things at the same time (conditional variable and sleep ending).
Maybe multithreading is not a good solution at all. Please share your approach in this case.
Thanks
Its not so much that multi-threading is a bad approach as your specific implementation is not right.
A call to the start() function or end() function will never return because they each call each other in a never ending recursion. This is already bad since your stack will be filling up as you enter deeper into function calls.
But that aside, your main loop starts a new thread when you call GAME_START and this new thread goes into its "forever" start()<-->end() loop. "OK" so far, but then when the TURN_END is called your main loop calls end() directly and therefore your main loop also now enters a forever start()<-->end() loop. This now means both your main and your "worker" thread are locked up in these loops that don't return - so no more messages can be processed from your socket.
I would suggest that your main loop uses a condition variable to signal your worker loop to force a new turn.
I am not quite sure what to suggest to replace your start()<-->end() recursion loop because its not clear to me what this is trying to achieve. But possibly a timer class might work here (the example is the first one I found in google)
Complete Example Using Stdin
Here the start function implements a thread loop instead of calling end/start repeatedly... Also the game ID 1 gets ended when you enter end the other games continue as normal. All games exit when you enter exit
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
std::vector<std::thread> games_threads;
std::condition_variable cv;
std::mutex cv_m;
int the_game_id = 0;
int start(int id) {
int game_id = id;
bool running = true;
while (running)
{
std::unique_lock<std::mutex> lk(cv_m);
auto now = std::chrono::system_clock::now();
std::cout << "THREAD " << game_id << ": Waiting for turn..." << std::endl;
// Wait for the signal to end turn only if the game ID is for us.
if(cv.wait_until(lk, now + std::chrono::seconds(10), [&game_id](){return (the_game_id == game_id || the_game_id == -1);}))
{
// Condition var signalled
if (the_game_id == -1)
{
std::cout << "THREAD" << game_id << ": end game - exit" << std::endl;
running = false;
}
else
{
std::cout << "THREAD" << game_id << ": turn end forced" << std::endl;
// Reset the game ID so we don't keep triggering
the_game_id = 0;
}
}
else
{
// 10 second timeout occured
std::cout << "THREAD" << game_id << ": 10 seconds is up, end turn" << std::endl;
}
}
std::cout << "THREAD" << game_id << ": ended" << std::endl;
return 1;
}
int main() {
// pretend socket implmementation - using stdin
int id = 1;
bool done = false;
while(!done) {
std::string cmd;
std::getline(std::cin, cmd);
if (cmd == "start")
{
std::cout << "starting..." << std::endl;
games_threads.push_back({ std::thread( [&id](){ return start(id++); } ) });
}
else if (cmd == "end")
{
std::cout << "ending..." << std::endl;
// Notify game ID 1 to end turn - (but in reality get the ID from the message)
the_game_id = 1;
cv.notify_all();
}
else if (cmd == "exit")
{
std::cout << "exiting all threads..." << std::endl;
// Notify game ID 1 to end turn
the_game_id = -1;
cv.notify_all();
done = true;
}
}
// Tidyup threads
for (auto &th : games_threads)
{
if (th.joinable())
{
th.join();
}
}
}
Output:
> start
starting...
THREAD 1: Waiting for turn...
> start
starting...
THREAD 2: Waiting for turn...
> start
starting...
THREAD 3: Waiting for turn...
> end
ending...
THREAD1: turn end forced
THREAD 1: Waiting for turn...
THREAD2: 10 seconds is up, end turn
THREAD 2: Waiting for turn...
THREAD3: 10 seconds is up, end turn
THREAD 3: Waiting for turn...
THREAD1: 10 seconds is up, end turn
THREAD 1: Waiting for turn...
> exit
exiting all threads...
THREAD1: end game - exit
THREAD1: ended
THREAD2: end game - exit
THREAD2: ended
THREAD3: end game - exit
THREAD3: ended

Condition Variable with a while loop in thread in C++

I'm trying to figure out how to use std::condition_variable in C++ implementing a "strange" producer and consumer program in which I had set a limit to the count variable.
The main thread ("producer") increments the count and must wait for this to return to zero to issue a new increment.
The other threads enters in a loop where they have to decrease the counter and issue the notification.
I am blocked because it is not clear to me how to conclude the program by orderly exiting the while loop inside the function of all threads.
Could someone give me some guidance on how to implement it, please?
Code
#include <iostream>
#include <thread>
#include <condition_variable>
#include <vector>
int main() {
int n_core = std::thread::hardware_concurrency();
std::vector<std::thread> workers;
int max = 100;
int count = 0;
std::condition_variable cv;
std::mutex mutex;
int timecalled = 0;
for (int i = 0; i < n_core; i++) {
workers.emplace_back(std::thread{[&max, &count, &mutex, &cv]() {
while (true) {
std::unique_lock<std::mutex> lk{mutex};
std::cout << std::this_thread::get_id() << " cv" << std::endl;
cv.wait(lk, [&count]() { return count == 1; });
std::cout << std::this_thread::get_id() << " - " << count << std::endl;
count--;
std::cout << std::this_thread::get_id() << " notify dec" << std::endl;
cv.notify_all();
}
}});
}
while (max > 0) {
std::unique_lock<std::mutex> lk{mutex};
std::cout << std::this_thread::get_id() << " cv" << std::endl;
cv.wait(lk, [&count]() { return count == 0; });
std::cout << std::this_thread::get_id() << " created token" << std::endl;
count++;
max--;
timecalled++;
std::cout << std::this_thread::get_id() << " notify inc" << std::endl;
cv.notify_all();
}
for (auto &w : workers) {
w.join();
}
std::cout << timecalled << std::endl; // must be equal to max
std::cout << count << std::endl; // must be zero
}
Problem
The program doesn't end because it is stuck on some final join.
Expected Result
The expected result must be:
100
0
Edits Made
EDIT 1 : I replaced max > 0 in the while with a true. Now the loops are unbounded, but using the solution of #prog-fh seems to work.
EDIT 2 : I added a variable to check the result in the end.
EDIT 3: I changed while(true) to while(max >0). Could this be a problem in concurrency because we are reading it without a lock?
The threads are waiting for something new in the call cv.wait().
But the only change that can be observed with the provided lambda-closure is the value of count.
The value of max must be checked too in order to have a chance to leave this cv.wait() call.
A minimal change in your code could be
cv.wait(lk, [&max, &count]() { return count == 1 || max<=0; });
if(max<=0) break;
assuming that changes to max always occur under the control of the mutex.
An edit to clarify around the accesses to max.
If the loop run by the threads is now while(true), then the max variable is only read in its body which is synchronised by mutex (thanks to lk).
The loop run by the main program is while (max > 0): max is read without synchronisation here but the only thread that can change this variable is the main program itself, so it's pure serial code from this perspective.
The whole body of this loop is synchronised by mutex (thanks to lk) so it is safe to change the value of max here since the read operations in the threads are synchronised in the same way.
You're having race conditions: in your code max may be read by multiple threads, whilst it is being modified in main, which is a race condition according to C++ standard.
The predicates you are using in wait seems to be incorrect (you're using ==).

Resolve deadlock issue, waiting in the main thread for multiple worker threads to finish (C++11)

I'm trying to write a program with c++11 in which multiple threads are run, and, during each cycle the main thread will wait for each thread to be finished. The program below is a testing program for this concept.
Apparently I'm missing something trivial in my implementation as it looks like I'm experiencing a deadlock (Not always, just during some random runs).
#include <iostream>
#include <stdio.h>
#include <thread>
#include <chrono>
#include <condition_variable>
#include <mutex>
using namespace std;
class Producer
{
public:
Producer(int a_id):
m_id(a_id),
m_ready(false),
m_terminate(false)
{
m_id = a_id;
m_thread = thread(&Producer::run, this);
// ensure thread is available before it is started
this_thread::sleep_for(std::chrono::milliseconds(100));
}
~Producer() {
terminate();
m_thread.join();
}
void start() {
//cout << "start " << m_id << endl;
unique_lock<mutex> runLock(m_muRun);
m_ready = true;
runLock.unlock();
m_cond.notify_all();
}
void wait() {
cout << "wait " << m_id << endl;
unique_lock<decltype(m_muRun)> runLock(m_muRun);
m_cond.wait(runLock, [this]{return !m_ready;});
}
void terminate() {
m_terminate = true;
start();
}
void run() {
do {
unique_lock<decltype(m_muRun)> runLock(m_muRun);
m_cond.wait(runLock, [this]{return m_ready;});
if (!m_terminate) {
cout << "running thread: " << m_id << endl;
} else {
cout << "exit thread: " << m_id << endl;
}
runLock.unlock();
m_ready = false;
m_cond.notify_all();
} while (!m_terminate);
}
private:
int m_id;
bool m_ready;
bool m_terminate;
thread m_thread;
mutex m_muRun;
condition_variable m_cond;
};
int main()
{
Producer producer1(1);
Producer producer2(2);
Producer producer3(3);
for (int i=0; i<10000; ++i) {
cout << i << endl;
producer1.start();
producer2.start();
producer3.start();
producer1.wait();
producer2.wait();
producer3.wait();
}
cout << "exit" << endl;
return 0;
}
The program's output when the deadlock is occurring:
....
.......
running thread: 2
running thread: 1
wait 1
wait 2
wait 3
running thread: 3
Looking at the program's output when the deadlock occurs, I suspect the bottleneck of the program is that sometimes the Producer::wait function is called, before the corresponding thread is actually started, i.e. the command Producer::start should have triggered the start, a.k. unlocking of the mutex, however it is not yet picked up by the thread's run method (Producer::run), (NB: I'm not 100% sure of this!). I'm a bit lost here, hopefully somebody can provide some help.
You have race condition in this code:
runLock.unlock();
m_ready = false;
m_ready variable must be always protected by mutex for proper synchronization. And it is completely unnecessary to wait for thread to start this_thread::sleep_for() - proper synchronization would take care of that as well so you can simply remove that line. Note this is pretty inefficient way of doing proper multithreading - there should be thread pool instead of individual object with separate mutex and condition variable each.

Having set amount of thread to work as consumers

I have created a producer / consumer code as following
class CTest{
public:
void producer( int i ){
unique_lock<mutex> l(m);
q.push(i);
if( q.size() )
cnd.notify_all();
}
void consumer(int i ){
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l );
}
if( q.empty())
return;
cout << "IM AWAKE :" << i << endl;
int tmp = q.front();
q.pop();
l.unlock();
cout << "Producer got " << tmp << endl;
}
void ConsumerInit( int threads ){
for( int i = 0; i < threads; i++ ){
thrs.push_back(thread(&CTest::consumer, this ,i));
}
}
void waitForTHreads(){
for( auto &a : thrs )
a.join();
}
void printQueue(){
while( ! q.empty()){
int tmp = q.front();
q.pop();
cout << "Queue got " << tmp << endl;
}
}
private:
queue<int> q;
vector<thread> thrs;
mutex m;
condition_variable cnd;
};
and main
int main(){
int x;
CTest t;
int counter = 0;
while( cin >> x ){
if( x == 0 ){
cout << "yay" << endl;;
break;
}
if( x == 1)
t.producer(counter++);
if( x == 2 )
t.ConsumerInit(5);
}
t.waitForTHreads();
t.printQueue();
return 0;
}
What this code does it , when user inputs "1" it will add number to the queue ,when user inputs "2" , 5 threads are spawned to retrieve data from queue and print it. However my problem is as followng , when i input
6 numbers , only 5 of them are printed due to fact that only 5 threads are spawned , what i want to do is thread to retrieve a data from queue , print int, and then again waiting if it can print another data. This way all N > 5 numbers would pri printed with just 5 threads.
My question is , what is standard way how to achieve this? I read few documens but didnt fint/cannot think of good solution. How are problems like this solved?
when i try to create simple thread pool :
void consumer(int i ){
while(true){
{
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l );
}
if( q.empty())
return;
cout << "IM AWAKE :" << i << endl;
int tmp = q.front();
q.pop();
cout << "Producer " << i << " got " << tmp << endl;
} //consumer(i);
}
}
and input N number all numbers are processed by one thread.
Thanks for help!
The current version of consumer can only read one value before exiting. In order to read more, it must loop, and this leads to your second version of consumer which has two problems:
Consumption here is so quick that the first thread into the queue can consume the whole queue within its timeslice (or however CPU is being allocated). Insert a yield or a sleep to force the OS to switch tasks.
The mutex is not unlocked so no other threads are able to get in.
Fortunately you aren't creating the threads until you need them and they terminate after the queue is empty so the whole deal with conditional_variable can go out the window.
void consumer(int i)
{
unique_lock<mutex> l(m);
while (!q.empty())
{
int tmp = q.front();
q.pop();
cout << i << " got " << tmp << endl;
// note: In the real world, locking around a cout is gross. cout is slow,
// so you want the unlock up one line. But...! This allows multiple threads
// to write to the consle at the same time and that makes your output
// look like it was tossed into a blender, so we'll take the performance hit
l.unlock(); // let other threads have a turn
this_thread::yield();
l.lock(); // lock again so the queue can be safely inspected
}
}
If you need to go with the threadpool approach, things get a little messier and the condition variable makes a return.
void consumer(int i)
{
while (true)
{
unique_lock<mutex> l(m);
if (q.empty())
{
cnd.wait(l);
}
if (!q.empty()) // OK. We got out of the conditional wait, but have
// other threads sucked the queue dry? Better check.
{
int tmp = q.front();
q.pop();
cout << i << " got " << tmp << endl;
}
l.unlock();
this_thread::yield();
}
}
An atomic<bool> terminated may be helpful to allow an orderly shutdown while (true) does not allow for.
In general, without going into code details, a threadpool is created and the threads are put in a wait state (waiting on one or more events / signals, or in your case condition_variable cnd;) - I'm used to work with events, so I'll use that in the following text, but a condition_variable should work in a similar way.
When a task is added to the queue, a task-event is set/fired and one ore more threads wake up (depending on the event (single / multi)).
When a thread wakes up, it checks (with a lock) if there is a task available, if available, executes the task and when finished checks again (!) if there are more tasks waiting. (because when you add 8 tasks in one go, 5 threads become active, so they need to check if there are more tasks after finishing their first one.
If there are no jobs left, the thread goes back in the wait state (waiting for a next job, or a quit event).
When quitting the application, another, say quit-event, is set for all threads (you can't just wait for the threads to finish, because the threads themselves are waiting on an event to do some work) -- or you could fire the same event, and first set a volatile variable, which the threads should then first check on any event to see if they need to quit, or do another job. Then you can wait for the threads to 'come home'.
A lock should be held as short as possible.
As for your code:
void producer( int i ){
unique_lock<mutex> l(m);
q.push(i);
if( q.size() )
cnd.notify_all();
}
Here the lock is held longer than needed (and perhaps too long). You also just pushed a value, so q will not be empty (no need to check). Since you only add one item (task), only one thread should be woken up (so notify_one() should be fine here).
So you should: lock, push, unlock, notify - instead of unlock, you can place the lock and push inside brackets, which will trigger an unlock in the unique_lock<> destructor.
void consumer(int i ){
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l );
}
if( q.empty())
return;
cout << "IM AWAKE :" << i << endl;
int tmp = q.front();
q.pop();
l.unlock();
cout << "Producer got " << tmp << endl;
}
Here you should lock, check queue, pop if there is a task, unlock, if no task, put the thread in a wait state again, else do work with the popped value (after unlocking), and then check again if there is more work to do. Normally it is not a good idea to call cout while the data is locked.. but for a small test you could get away with it, especially because cout needs to be synchronized too (but it would be cleaner to synchronize cout on its own, separate from your data lock).
void printQueue(){
while( ! q.empty()){
int tmp = q.front();
q.pop();
cout << "Queue got " << tmp << endl;
}
}
Make sure your data is locked here too! (although it's only called from main after the threads have finished, the function is in your class, and the data should be locked).

Still having race condition with boost::mutex

I am trying an example, which causes race condition to apply the mutex. However, even with the mutex, it still happens. What's wrong? Here is my code:
#include <iostream>
#include <boost/thread.hpp>
#include <vector>
using namespace std;
class Soldier
{
private:
boost::thread m_Thread;
public:
static int count , moneySpent;
static boost::mutex soldierMutex;
Soldier(){}
void start(int cost)
{
m_Thread = boost::thread(&Soldier::process, this,cost);
}
void process(int cost)
{
{
boost::mutex::scoped_lock lock(soldierMutex);
//soldierMutex.lock();
int tmp = count;
++tmp;
count = tmp;
tmp = moneySpent;
tmp += cost;
moneySpent = tmp;
// soldierMutex.unlock();
}
}
void join()
{
m_Thread.join();
}
};
int Soldier::count, Soldier::moneySpent;
boost::mutex Soldier::soldierMutex;
int main()
{
Soldier s1,s2,s3;
s1.start(20);
s2.start(30);
s3.start(40);
s1.join();
s2.join();
s3.join();
for (int i = 0; i < 100; ++i)
{
Soldier s;
s.start(30);
}
cout << "Total soldier: " << Soldier::count << '\n';
cout << "Money spent: " << Soldier::moneySpent << '\n';
}
It looks like you're not waiting for the threads started in the loop to finish. Change the loop to:
for (int i = 0; i < 100; ++i)
{
Soldier s;
s.start(30);
s.join();
}
edit to explain further
The problem you saw was that the values printed out were wrong, so you assumed there was a race condition in the threads. The race in fact was when you printed the values - they were printed while not all the threads had a chance to execute
Based on this and your previous post (were it does not seem you have read all the answers yet). What you are looking for is some form of synchronization point to prevent the main() thread from exiting the application (because when the main thread exits the application all the children thread die).
This is why you call join() all the time to prevent the main() thread from exiting until the thread has exited. As a result of your usage though your loop of threads is not parallel and each thread is run in sequence to completion (so no real point in using the thread).
Note: join() like in Java waits for the thread to complete. It does not start the thread.
A quick look at the boost documentation suggests what you are looking for is a thread group which will allow you to wait for all threads in the group to complete before exiting.
//No compiler so this is untested.
// But it should look something like this.
// Note 2: I have not used boost::threads much.
int main()
{
boost::thread_group group;
boost::ptr_vector<boost::thread> threads;
for(int loop = 0; loop < 100; ++loop)
{
// Create an object.
// With the function to make it start. Store the thread in a vector
threads.push_back(new boost::thread(<Function To Call>));
// Add the thread to the group.
group.add(threads.back());
}
// Make sure main does not exit before all the threads have completed.
group.join_all();
}
If we go back to your example and retrofit your Soldier class:
int main()
{
boost::thread batallion;
// Make all the soldiers part of a group.
// When you start the thread make the thread join the group.
Soldier s1(batallion);
Soldier s2(batallion);
Soldier s3(batallion);
s1.start(20);
s2.start(30);
s3.start(40);
// Create 100 soldiers outside the loo
std::vector<Soldier> lotsOfSoldiers;
lotsOfSoldiers.reserve(100); // to prevent reallocation in the loop.
// Because you are using objects we need to
// prevent copying of them after the thread starts.
for (int i = 0; i < 100; ++i)
{
lotsOfSoldiers.push_back(Solder(batallion));
lotsOfSoldiers.back().start(30);
}
// Print out values while threads are still running
// Note you may get here before any thread.
cout << "Total soldier: " << Soldier::count << '\n';
cout << "Money spent: " << Soldier::moneySpent << '\n';
batallion.join_all();
// Print out values when all threads are finished.
cout << "Total soldier: " << Soldier::count << '\n';
cout << "Money spent: " << Soldier::moneySpent << '\n';
}