Program with a separate thread is being killed - c++

After declaring an object in my main and running its function in a separate thread, my program crashes.
I have read other question on SO but due to my lack of knowledge in multithreading, I cannot understand what is my specific problem.
Here is my class called UART (without header files and only showing the required cpp declaration):
void UART::run()
{
while(true)
{
_letter = _serial.read();
if (_letter == "!")
{
_line = _serial.readline();
_words.clear();
std::istringstream f(_line);
std::string s;
//std::cout << _letter << std::endl;
while (getline(f,s,'\t'))
{
_words.push_back(s);
}
this->fillVars();
}
}
}
void UART::fillVars()
{
if (_words[0] == "s")
{
_effort[0] = std::stoi(_words[1]);
_effort[1] = std::stoi(_words[2]);
}
else if (_words[0] == "e")
{
this->convertToMeters();
}
}
void UART::convertToMeters()
{
std::cout << _position[0];
_position[0] = std::stod(_words[1]); // / _tick_meters;
_position[1] = std::stod(_words[2]) / _tick_meters;
}
double UART::getPosition(std::string wheel)
{
if (wheel == "LEFT") return _position[0];
else return _position[1];
}
And my main cpp looks like this:
int main(int argc, char** argv)
{
ros::init(argc, argv, "joint_node");
std::string port("/dev/ttyACM0");
unsigned long baud = 115200;
try
{
serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000));
if(my_serial.isOpen()) ROS_INFO("Serial is %s", "open");
genius::UART uart(my_serial, 380);
std::thread uart_run(&genius::UART::run, uart);
std::cout << uart.getPosition("LEFT") <<std::endl;
} catch (std::exception &e)
{
std::cerr << "Unhandled Exception: " << e.what() << std::endl;
}
return 0;
}
My understanding is that after creating an object uart, I want to run its function run() in a separate thread as I want its values to be updated with no interruption on a background. So whenever I access its values like using its function uart.getPosition("LEFT") I will get the last up-to date data. I guess I do not need .join() this thread as I do not want to wait for it as it never ends.
But for some reason after calling the uart.getPosition("LEFT") my program crashes and also function getPosition() never gets executed and I always get value of 0.

Related

Exit program when catch exception from thread

Referring to Catching exception from worker thread in the main thread, I created a worker thread that throws exception to main thread and then terminates the program (the logic is to exit program upon exception happens).
I didn't seems to be implementing it correctly, as the program won't execute till the line where exit() was called.
Sample code:
#include <thread>
#include <iostream>
#include <stdexcept>
static std::exception_ptr _exceptionPtr = nullptr;
struct WorkerThread
{
std::thread thread;
void doSomething()
{
int seconds = 0;
bool shouldStop = false;
while(shouldStop == false)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "time passed : " << ++seconds << "seconds" << std::endl;
if (seconds == 10) // something bad happened 10 seconds later
{
try
{
shouldStop = true;
throw std::runtime_error("something really bad happened");
}
catch (const std::runtime_error &ex)
{
_exceptionPtr = std::current_exception();
}
}
}
}
void run()
{
thread = std::thread([this] { doSomething(); });
thread.detach();
}
};
int main(int argc, char *argv[])
{
WorkerThread workerThread;
try
{
workerThread.run();
}
catch (...)
{
if (_exceptionPtr)
{
try
{
std::rethrow_exception(_exceptionPtr);
}
catch (std::runtime_error &ex)
{
// terminates program if exception happens
std::cout << "Program will now exit" << std::endl;
exit(EXIT_FAILURE); // but program never executes till here
}
}
}
for (;;)
{
// do A
// do B
// do C
// do ...
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "waiting for thread..." << std::endl;
}
return 0;
}
What did i miss ? Is the current approach correct ? If no, how do i do it correctly ? thanks
In the code you posted, the exception check is happening only once, and possibly before the thread has been launched.
Also you're catching an error from the host thread but the error you're throwing is on the second thread.
I fixed these issues, by waiting for the second thread to finish before checking the exception.
Anyways, the paradigmatic way to throw an exception across a thread can be found here: How can I propagate exceptions between threads?
#include <thread>
#include <iostream>
#include <stdexcept>
static std::exception_ptr _exceptionPtr = nullptr;
struct WorkerThread
{
std::thread thread;
void doSomething()
{
int seconds = 0;
bool shouldStop = false;
while (shouldStop == false)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "time passed : " << ++seconds << "seconds" << std::endl;
if (seconds == 10) // something bad happened 10 seconds later
{
try
{
shouldStop = true;
throw std::runtime_error("something really bad happened");
}
catch (const std::runtime_error &ex)
{
_exceptionPtr = std::current_exception();
}
}
}
}
void run()
{
thread = std::thread([this] { doSomething(); });
//thread.detach();
}
};
int main(int argc, char *argv[])
{
WorkerThread workerThread;
workerThread.run();
workerThread.thread.join();
if (_exceptionPtr)
{
try
{
std::rethrow_exception(_exceptionPtr);
}
catch (std::runtime_error &ex)
{
// terminates program if exception happens
std::cout << "Program will now exit" << std::endl;
exit(EXIT_FAILURE); // but program never executes till here
}
}
for (;;)
{
// do A
// do B
// do C
// do ...
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "waiting for thread..." << std::endl;
}
return 0;
}
Exception should be caught at the for loop instead of workerThread.run(), since run() will exit immediately.
#include <thread>
#include <iostream>
#include <stdexcept>
static std::exception_ptr _exceptionPtr = nullptr;
struct WorkerThread
{
std::thread thread;
void doSomething()
{
int seconds = 0;
bool shouldStop = false;
while (shouldStop == false)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "time passed : " << ++seconds << "seconds" << std::endl;
if (seconds == 10) // something bad happened 10 seconds later
{
try
{
shouldStop = true;
throw std::runtime_error("something really bad happened");
}
catch (const std::runtime_error &ex)
{
_exceptionPtr = std::current_exception();
}
}
}
}
void run()
{
thread = std::thread([this] { doSomething(); });
thread.detach();
}
};
int main(int argc, char *argv[])
{
WorkerThread workerThread;
workerThread.run();
for (;;)
{
// do A
// do B
// do C
// do ...
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "waiting for thread..." << std::endl;
if (_exceptionPtr)
{
try
{
std::rethrow_exception(_exceptionPtr);
}
catch (std::runtime_error &ex)
{
// terminates program if exception happens
std::cout << "Program will now exit" << std::endl;
exit(EXIT_FAILURE); // but program never executes till here
}
}
}
return 0;
}
Credits to #liliscent

std::async and std::shared_future causes the program to fall

I am trying to run some function in asynchronous manner. For this purpose I wrote class called Core where I use std::async to run function in different thread and std::shared_future<int> to wait for this thread and possibly to get future result. This is code of test program:
#include <iostream>
#include <future>
class Core : public std::enable_shared_from_this<Core>
{
public:
Core()
: isRunning_(false) {
};
~Core() {
isRunning_ = false;
if (f_.valid())
{
f_.wait();
std::cout << "Result is: " << f_.get() << std::endl;
}
};
void Start() {
isRunning_ = true;
auto self(shared_from_this());
f_ = std::async(std::launch::async, [self, this]() {
try {
while (true) {
if (!isRunning_)
break;
std::cout << "Boom" << std::endl; // Error occurs here
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
catch (const std::exception& e) {
std::cerr << "Loop error:" << e.what();
}
return 999;
});
}
private:
std::shared_future<int> f_;
std::atomic<bool> isRunning_;
};
int main()
{
try {
std::shared_ptr<Core> load(new Core);
load->Start();
throw std::runtime_error("Generate error"); // Added in order to generate error
}
catch (const std::exception& e) {
std::cout << "Error occurred: " << e.what();
}
return 0;
}
Each time when I start this program it crashes at this line:
std::cout << "Boom" << std::endl; // Error occurs here
with this error:
That is debugger error and call stack which I managed to get during debugging:
Looks like Core destructor function doesn't call at all. Why is it happens? weird!!!
Could you tell me where is my mistake? Thanks.
When main thread returns from main() it starts tearing down the environment before terminating the whole process. All this while background thread is accessing objects there are being destroyed or have been destroyed already.
I am not sure what you are triying to achieve, but you are doing something wrong:
Your lambda should execute some work and return immediately after it is done e.g. you should never loop forever.
Your main thread should wait for your future to complete by calling std::future<T>::get().

What is the correct way to run tracking software and a server concurrently? (OpenCV 3)

I have written a basic server in C++ that runs in an infinite while loop. It receives signals from a client to do things. The main process that I want is to initiate or stop some tracking software that I have written.
I would like the server to still be able to receive signals while the tracking software is being run (e.g. if a stop signal was given). I figured that the best way to do this would be to create a separate thread for the tracking software, so that is what I did:
void Server::tracking(Command c)
{
//I have since changed this method. The new implementation is below
//switch(c) {
// case START:
// player = VideoPlayer();
// player.setTrackStatus(true);
// t = std::thread(&Server::track, this);
// t.detach();
// break;
// case STOP:
// player.setTrackStatus(false);
// break;
// default:
// break;
//}
}
Server::track just calls player.run()
VideoPlayer is the class that contains the main tracking loop. The track status is what determines whether or not the tracking loop continues to execute.
This works fine the first time I run it, it is able to start the tracking and stop it. The problem arises when I try to send another "START" signal without restarting the server.
I have narrowed down the problem to the cv::namedWindow function.
Here is the start of the VideoPlayer class:
void VideoPlayer::run(void)
{
//I have since changed this method. The new implementation is below
//initVC();
//openStream();
}
initVC() is where I create the namedWindow and openStream contains the main tracking loop. Here is initVC (which is where I believe the problem lies):
void VideoPlayer::initVC()
{
if(!capture.open("cut.mp4")) {
throw "Cannot open video stream";
}
std::cout << "flag 1" << std::endl;
cv::namedWindow("Tracker", CV_WINDOW_AUTOSIZE);
std::cout << "flag 2" << std::endl;
}
I have found that on the second run (i.e. tracking has been started and stopped and the server has not been closed and reopened), that flag 2 never gets run. I also found that, if I omit namedWindow then the program stops before imshow(). It might also be worth noting that the program doesn't crash, it just seems to pause.
I have a feeling that I am doing something wrong with the threading, because I have never used threads in C++ before.
Thanks!
EDIT: I have been attempting to add some of the changes suggested by #Dom, however I am still having a similar issue to before. I will post some additional code below with comments to try to explain.
Server::tracking:
This is meant to initiate tracking based on the command received from the client.
void Server::tracking(Command c)
{
switch(c) {
case START:
if(!isRunning) {
player = make_unique<VideoPlayer>();
isRunning = true;
player->setTrackStatus(isRunning);
}
else {
std::lock_guard<std::mutex> lock(mtx);
}
break;
case STOP:
if(isRunning) {
player->terminate();
player->exit(); //Destroys OpenCV stuff
player->joinThread();
player = nullptr;
isRunning = false;
}
else {
std::lock_guard<std::mutex> lock(mtx);
}
break;
default:
break;
}
}
VideoPlayer Constructor:
VideoPlayer::VideoPlayer () : trackStatus(true)
{
tracker = Tracker(); //A separate class, related to the data from the tracked
//object. Not relevant to the current question
track_t = std::thread(&VideoPlayer::run, this);
return;
}
VideoPlayer::run:
void VideoPlayer::run(void)
{
std::lock_guard<std::mutex> lock(mtx);
initVC(); //Initialises the OpenCV VideoCapture
openStream(); //Contains the main tracking code
return;
}
VideoPlayer::openStream:
void VideoPlayer::openStream()
{
while(trackStatus) {
... //tracking stuff
}
return;
}
VideoPlayer::terminate:
void VideoPlayer::terminate()
{
track = false;
std::lock_guard<std::mutex> lock(mtx);
}
VideoPlayer::joinThread:
void VideoPlayer::joinThread()
{
if(track_t.joinable()) {
std::cout << "flag 1" << std::endl;
track_t.join();
std::cout << "flag 2" << std::endl; //It fails here on my second "run"
return;
}
}
Basically, my program stops just before the track_t.join(), the second time I run the tracking (without restarting the server). flag 1 and flag 2 print the first time that I run the tracking. All of the OpenCV components appear to have been disposed of correctly. If I then try to open the tracking again, firstly, the tracking doesn't seem to start (but the program doesn't crash), and then if I try to stop the tracking, it prints flag 1 but then stops indefinitely without printing flag 2
Sorry for the lengthy post. I hope this gives a bit more context to what I'm trying to achieve
So your tracking app. could be implemented as follows:
#include <chrono>
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <memory>
#include <atomic>
enum Command : char
{
START = '1',
STOP = '0'
};
static std::mutex mtx; // mutex for I/O stream
class VideoPlayer
{
public:
VideoPlayer() : trackStatus()
{
initVC();
openStream();
};
~VideoPlayer()
{
closeStream();
uninitVC();
}
void setTrackStatus(bool status)
{
if (status && trackStatus == false)
{
trackStatus = status;
t = std::thread(&VideoPlayer::run, this);
}
else
{
trackStatus = false;
if (t.joinable())
{
t.join();
}
}
}
private:
void run()
{
tId = std::this_thread::get_id();
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "run thread: " << tId << std::endl;
}
while (trackStatus)
{
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "...running thread: " << tId << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1)); // encode chunk of stream and play, whatever....
}
}
void initVC()
{
/*
if (!capture.open("cut.mp4"))
{
throw "Cannot open video stream"; --> http://stackoverflow.com/questions/233127/how-can-i-propagate-exceptions-between-threads
}
std::cout << "flag 1" << std::endl;
//cv::namedWindow("Tracker", CV_WINDOW_AUTOSIZE);
//std::cout << "flag 2" << std::endl;
*/
}
void uninitVC()
{
}
void openStream()
{
}
void closeStream()
{
}
private:
std::atomic<bool> trackStatus; // atomic, because of access from another (main) thread
std::thread t; // thread for "tracking"
std::thread::id tId; // ID of the "tracking" thread
};
class Server
{
public:
Server() : isRunning(), player(std::make_unique<VideoPlayer>())
{
}
~Server() = default;
void tracking(Command c)
{
switch (c)
{
case START:
if (!isRunning)
{
isRunning = true;
player->setTrackStatus(isRunning);
}
else
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Player is already running...\n";
}
break;
case STOP:
if (isRunning)
{
player->setTrackStatus(!isRunning);
isRunning = false;
}
else
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Player is not running...\n";
}
break;
default:
break;
}
}
private:
std::unique_ptr<VideoPlayer> player;
bool isRunning;
};
int main()
{
std::cout << "main thread: " << std::this_thread::get_id() << std::endl;
Server srv;
char cmd = -1;
while (std::cin >> cmd)
{
switch (cmd)
{
case Command::START:
{
srv.tracking(Command::START);
}
break;
case Command::STOP:
{
srv.tracking(Command::STOP);
}
break;
default:
std::cout << "Unknown command...\n";
break;
}
}
}
You can move creation of the thread to constructor of VideoPlayer and join in destructor (I would prefer it...):
VideoPlayer() : trackStatus(true)
{
initVC();
openStream();
t = std::thread(&VideoPlayer::run, this);
};
~VideoPlayer()
{
closeStream();
uninitVC();
if (t.joinable())
{
t.join();
}
}
but some modifications are needed to terminate and clean the thread, you can use something like
public:
void VideoPlayer::terminate()
{
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "terminate thread: " << tId << std::endl;
}
trackStatus = false;
}
however, than is needed to create instance of player during START
player = std::make_unique<VideoPlayer>();
and then Terminate() and delete the player during STOP
player->terminate();
player = nullptr;
Hope, this inspired you enough ;-)

C++ boost threadgroup.interrupt_all() causing main thread to exit too

I'm using the below code to create threads and add them to a thread pool. The threads load fine and each perform a simple looping routine until the main thread calls ResetWorkerThreads a second time and kills off the sub threads. The sub threads are interrupted however the main thread exits also. There are no errors written to console. I can't wrap my head around it as it doesn't appear to have any exception and the main thread has not been added to the vecThreads thread pool. Also the second time this function is all the "All Threads Killed" is not outputted as if it never reaches that point.
std::string strPreviousSettings = "0";
std::string strPreviousAgentSettings = "0";
bool boolResetWorkers;
std::string strIP;
std::string strMACAddress;
boost::thread_group vecThreads;
std::string GetIP()
{
std::string strIP;
try
{
using namespace boost::network;
std::string strRequest;
http::client client;
http::client::request request("http://test.com/ip.php");
http::client::response response = client.get(request);
strIP = body(response);
}
catch(...)
{
cout << "GetLocalIP - Error: " << endl;
}
return strIP;
}
std::string getMacAddress()
{
std::string strMACAddress = GetFileContents("/sys/class/net/eth0/address");
boost::replace_all(strMACAddress, ":", "");
boost::replace_all(strMACAddress, "\n", "");
return strMACAddress;
}
void ThreadSettingsWorker()
{
int x = 1;
strIP = GetIP();
strMACAddress = getMacAddress();
do {
CheckEventSettings();
CheckAgentSettings();
if(boolResetWorkers==true)
{
ResetWorkerThreads();
} else {
boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
}
} while ( x != 0 );
}
void ResetWorkerThreads()
{
cout << "Resetting Workers Threads\n";
boolResetWorkers = false;
int intWorkerCount = 10; //Spawn 10 workers
int X = 0;
int intI = 1;
cout << "Kill All Threads\n";
try
{
vecThreads.interrupt_all();
}
catch(...)
{
//std::cerr << "Kill All Threads: " << std::endl;
}
cout << "All Threads Killed\n";
for (int i = 0; i < intWorkerCount; ++i)
{
cout << "Starting Worker: " << (i + 1) << "\n";
boost::thread tWorker(&ThreadWorker, (i + 1));
vecThreads.add_thread(&tWorker);
}
}
void TestRequest()
{
try
{
using namespace boost::network;
std::stringstream ss;
http::client client;
ss << "http://test.com/sadasdasd.html";
http::client::request request(ss.str());
http::client::response response = client.get(request);
std::string strOutput = body(response);
cout << "Test Request Out: " << strOutput << "\n";
}
catch(...)
{
cout << "TestRequest - Error: " << endl;
return;
}
}
void ThreadWorker(int intThread)
{
try
{
int X = 0;
do {
cout << "Thread " << intThread << "\n";
TestRequest();
} while ( X != 55 );
}
catch(...)
{
}
}
void CheckEventSettings()
{
try
{
using namespace boost::network;
std::string strRequest;
http::client client;
http::client::request request("http://test.com/events.php");
http::client::response response = client.get(request);
std::string strOutput = body(response);
if(strPreviousSettings==strOutput)
{
cout << "No Event Settings Changes\n";
} else {
cout << "Applying New Event Settings\n";
strPreviousSettings = strOutput;
std::string strDividerLine = "<br>";
std::string strDividerField = "<field>";
std::vector<std::string> vEvents;
vEvents = EasySplit(strOutput, strDividerLine);
for(std::vector<std::string>::const_iterator iEvent = vEvents.begin(); iEvent != vEvents.end() - 1; ++iEvent) {
}
}
}
catch(...)
{
cout << "CheckEventSettings - Error: " << endl;
return;
}
}
void CheckAgentSettings()
{
try
{
using namespace boost::network;
std::stringstream ss;
http::client client;
ss << "http://test.com/checksettings.php";
http::client::request request(ss.str());
http::client::response response = client.get(request);
std::string strOutput = body(response);
if(strPreviousAgentSettings==strOutput)
{
cout << "No Agent Settings Changes\n";
} else {
cout << "Applying New Agent Settings\n";
strPreviousAgentSettings = strOutput;
boolResetWorkers = true;
}
}
catch(...)
{
cout << "CheckAgentSettings - Error: " << endl;
return;
}
}
int main()
{
// Start thread
boost::thread tCheckSettings(&ThreadSettingsWorker);
// Ask thread to stop
//tCheckSettings.interrupt();
// Join - wait when thread actually exits
tCheckSettings.join();
return 0;
}
You have an error here:
boost::thread tWorker(&ThreadWorker, (i + 1));
vecThreads.add_thread(&tWorker);
You create a local object tWorker that is deleted just after call to add_thread(). So vecThreads contains the dangling pointers to threads. When you call vecThreads.interrupt_all() you get undefined behavior because vecThreads tries to access the deleted thread objects and I suppose your program just terminates because of access violation or something.
You have to change your code to something like this:
boost::thread* ptWorker = new boost::thread(&ThreadWorker, (i + 1));
vecThreads.add_thread(ptWorker);
Please note that you don't need to delete those thread objects yourself. thread_group will delete them itself.
ADDITION:
The problem with terminate() may be caused by destructor of http::client throwing an exception. Please try this to possibly eliminate that problem in TestRequest():
try{
http::client client;
try{
// other code
}
catch (){}
}
catch(){}
Also I'd suggest resetting vecThreads after interrupt_all(). For example you can define it as boost::scoped_ptr and then do pvecThreads.reset(new boost::thread_group()) after the call to interrupt_all().
At present the interrupted threads still remain in the thread_group after the interruption and then you try to interrupt them again along with the new threads added to the thread_group later in ResetWorkerThreads().
Inside of ResetWorkerThreads You have:
for (int i = 0; i < intWorkerCount; ++i)
{
cout << "Starting Worker: " << (i + 1) << "\n";
// One issue is here, don't create a thread on the stack
// and pass it to the thread group use new instead!
boost::thread tWorker(&ThreadWorker, (i + 1));
vecThreads.add_thread(&tWorker);
}
You are adding a thread created on the stack to the thread group. As soon as you iterate over the loop that threads memory is invalidated. You will need to new the thread and pass that pointer to add_thread.

Thread on Windows

I have a small question about threading in Windows. I have the following code :
main.cpp
int main(int ac, char **av)
{
std::vector<Mthread *> mythread;
std::list<std::string> stack;
DWORD id = 0;
stack.push_back("Maison");
stack.push_back("Femmes");
stack.push_back("Fetes");
stack.push_back("Voitures");
stack.push_back("Nounours");
while (id != 5)
{
mythread.push_back(new Mthread());
mythread[mythread.size() - 1]->initThread(&stack, id);
id++;
}
id = 0;
while (id != 5)
{
WaitForInputIdle(mythread[id]->getThread(), INFINITE);
id++;
}
return (1);
}
and Mthread.cpp who is creating my Mthread class.
Mthread::Mthread() {}
Mthread::~Mthread() {}
HANDLE Mthread::getThread(void) const
{
return (this->thread);
}
bool Mthread::initThread(std::list<std::string> *list, DWORD ID)
{
this->save = list;
this->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Mthread::ThreadFunc, (LPVOID)list, 0, &ID);
if (this->thread == NULL)
{
std::cout << "Erreur lors du lancement du thread" << std::endl;
return (false);
}
else
{
return (true);
}
}
void Mthread::ThreadFunc(LPVOID list)
{
std::cout << " is launch" << std::endl;
}
The code is working, but I have a small problem : no string is written on the terminal.
But, if I change my code to :
bool Mthread::initThread(std::list<std::string> *list, DWORD ID)
{
this->save = list;
this->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Mthread::ThreadFunc, (LPVOID)list, 0, &ID);
if (this->thread == NULL)
{
std::cout << "Erreur lors du lancement du thread" << std::endl;
return (false);
}
else
{
std::cout << "OK" << std::endl;
return (true);
}
}
Well "OK" and "is launch" is written 5 times on the terminal. I don't understand why.
When I pass a small string a to cout it seems to be working, but when I don't nothing is written.
short answer: I guess your main() terminates before the threads have a chance to run. add a sleep() or something similar to main.
More complex answer:
- threads and main run independently from eachother. You have to wait in your main until you know you can exit main.
- your program tends to be unsafe since the vector is accessed by all threads without any synchronisation. Read up on locks, mutexes and semaphores!
Before terminating, your program should wait until the threads have finished their job. On windows, take a look at WaitForMultipleObjects.