Basically, I have two threads:
ONE: gets messages from the user, and adds them to the queue. - notifies the other thread that there's a message in the queue/
TWO: handles the messages and prints them out, waits for the other thread to notify them:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
void getMessages();
void handleMessages();
using namespace std;
queue<int> msgQueue;
mutex mLock;
condition_variable con;
int main(void)
{
thread msgHandle(handleMessages);
getMessages();
msgHandle.join();
}
// getting messages from user
void getMessages()
{
int num = 0;
do
{
// getting number from user
cin >> num;
// adding number to queue
mLock.lock();
msgQueue.push(num);
mLock.unlock();
// notifying
con.notify_one();
} while (num != -1);
}
// handles the message queue
void handleMessages()
{
int curNum = 0;
do
{
// waiting for reply
unique_lock<mutex> uLock(mLock);
try
{
con.wait(uLock);
}
catch (...)
{
break;
}
// printing message from queue
curNum = msgQueue.front();
msgQueue.pop();
cout << "Number: " << curNum << endl;
} while (curNum != -1);
}
My question is how can I abort the wait part if I exit the application manually (X button)
Related
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
std::mutex g_m;
std::string messageGlobal = "";
void threadFunc() // run in the log thread
{
while (1)
{
g_m.lock();
if (messageGlobal != "")
{
// logging takes a long time
sleep(10000)
cout << messageGlobal << endl;
messageGlobal = "";
}
g_m.unlock();
}
}
// logging api
void log(const string& message)
{
g_m.lock();
messageGlobal = message;
g_m.unlock();
}
int main()
{
std::thread th(threadFunc);
log("Hello world!");
log("Hello World2!");
log("Hello World3!");
log("Hello World4!");
// Important work
th.join();
return 0;
}
New to threading here and I don't understand why only the last message is being printed.
The two threads here are main thread and an extra thread which runs permanently and outputs to the screen whenever there is a message to be printed.
Would appreciate if someone shows me where I went wrong.
Edit: the goal is for the code in "important code" to execute while the very long logging function takes place.
As other people suggested, you'd better use a queue to hold the messages and synchronize the access of the message queue between threads. However, here is a simple fix of your code here:
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
std::mutex g_m;
std::string messageGlobal = "";
bool g_all_done = false;
void threadFunc() // run in the log thread
{
while (1)
{
g_m.lock();
if (messageGlobal != "")
{
cout << messageGlobal << endl;
messageGlobal = "";
}
bool all_done = g_all_done;
g_m.unlock();
if (all_done) break;
}
}
// logging api
void log(const string& message)
{
bool logged = false;
do {
g_m.lock();
if (messageGlobal == "") {
messageGlobal = message;
logged = true;
}
g_m.unlock();
} while(!logged);
}
void all_done() {
g_m.lock();
g_all_done = true;
g_m.unlock();
}
int main()
{
std::thread th(threadFunc);
log("Hello world!");
log("Hello World2!");
log("Hello World3!");
log("Hello World4!");
all_done(); // this tells the print thread to finish.
th.join();
return 0;
}
Would appreciate if someone shows me where I went wrong.
You are wrong in assumption that threads would lock mutex in order, which is not guaranteed. So what happened that the same thread (main) locked the mutex multiple times and modified the message multiple times and second thread only had a chance to print the last message. To make it work you should make main thread to wait until message is emptied and only then to publish again, but most probably you should do that using condition variable as otherwise you would peg CPU doing this in code as written. And even better to create a queue of log messages and only wait when queue is full.
Note that you are missing condition for log thread to finish so th.join(); would hang.
Here is example on how it could work with single message:
std::mutex g_m;
std::condition_variable g_notifyLog;
std::condition_variable g_notifyMain;
bool g_done = false;
std::string messageGlobal = "";
void threadFunc() // run in the log thread
{
while (1)
{
std::lock_guard<std::mutex> lk( g_m );
g_notifyLog.wait( g_m, []() { return !messageGlobal.empty() || g_done; } );
if( g_done ) break;
cout << messageGlobal << endl;
messageGlobal = "";
g_notifyMain.notify_one();
}
}
// logging api
void log(const string& message)
{
std::lock_guard<std::mutex> lk( g_m );
g_notifyMain.wait( g_m, []() { return messageGlobal.empty(); } );
messageGlobal = message;
g_notifyLog.notify_one();
}
void stop_log()
{
std::lock_guard<std::mutex> lk( g_m );
g_done = true;
g_notifyLog.notify_one();
}
You didn't implement any mechanism that ensures that the threads operate interleaved. It is much more likely that the thread that unlocked mutex will be the one to lock it in the next moment as locking mutex/unlocking mutexes are fast operations unless sleep/wait is triggered.
Furthermore, the ThreadFunc is an endless loop. So it theoretically the program might just run the loop repeatedly without letting any execution of log to trigger.
You need to utilise std::condition_variable to signal between threads when data is available for logging and rewrite log method so it won't overwrite existing data-to-be-printed.
I've implemented thread pooling following the answer of Kerrek SB in this question.
I've implemented MPMC queue for the functions and vector threads for the threads.
Everything worked perfectly, except that I don't know how to terminate the program, in the end if I just do thread.join since the thread is still waiting for more tasks to do, it will not join and the main thread will not continue.
Any idea how to end the program correctly?
For completeness, this is my code:
function_pool.h
#pragma once
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
class Function_pool
{
private:
std::queue<std::function<void()>> m_function_queue;
std::mutex m_lock;
std::condition_variable m_data_condition;
public:
Function_pool();
~Function_pool();
void push(std::function<void()> func);
std::function<void()> pop();
};
function_pool.cpp
#include "function_pool.h"
Function_pool::Function_pool() : m_function_queue(), m_lock(), m_data_condition()
{
}
Function_pool::~Function_pool()
{
}
void Function_pool::push(std::function<void()> func)
{
std::unique_lock<std::mutex> lock(m_lock);
m_function_queue.push(func);
// when we send the notification immediately, the consumer will try to
get the lock , so unlock asap
lock.unlock();
m_data_condition.notify_one();
}
std::function<void()> Function_pool::pop()
{
std::unique_lock<std::mutex> lock(m_lock);
m_data_condition.wait(lock, [this]() {return !m_function_queue.empty();
});
auto func = m_function_queue.front();
m_function_queue.pop();
return func;
// Lock will be released
}
main.cpp
#include "function_pool.h"
#include <string>
#include <iostream>
#include <mutex>
#include <functional>
#include <thread>
#include <vector>
Function_pool func_pool;
void example_function()
{
std::cout << "bla" << std::endl;
}
void infinite_loop_func()
{
while (true)
{
std::function<void()> func = func_pool.pop();
func();
}
}
int main()
{
std::cout << "stating operation" << std::endl;
int num_threads = std::thread::hardware_concurrency();
std::cout << "number of threads = " << num_threads << std::endl;
std::vector<std::thread> thread_pool;
for (int i = 0; i < num_threads; i++)
{
thread_pool.push_back(std::thread(infinite_loop_func));
}
//here we should send our functions
func_pool.push(example_function);
for (int i = 0; i < thread_pool.size(); i++)
{
thread_pool.at(i).join();
}
int i;
std::cin >> i;
}
Your problem is located in infinite_loop_func, which is an infinite loop and by result doesn't terminate. I've read the previous answer which suggests throwing an exception, however, I don't like it since exceptions should not be used for the regular control flow.
The best way to solve this is to explicitly deal with the stop condition. For example:
std::atomic<bool> acceptsFunctions;
Adding this to the function pool allows you to clearly have state and to assert that no new functions being added when you destruct.
std::optional<std::function<void()>> Function_pool::pop()
Returning an empty optional (or function in C++14 and before), allows you to deal with an empty queue. You have to, as condition_variable can do spurious wakeups.
With this, m_data_condition.notify_all() can be used to wake all threads.
Finally we have to fix the infinite loop as it doesn't cover overcommitment and at the same time allows you to execute all functions still in the queue:
while (func_pool.acceptsFunctions || func_pool.containsFunctions())
{
auto f = func_pool.pop();
If (!f)
{
func_pool.m_data_condition.wait_for(1s);
continue;
}
auto &function = *f;
function ();
}
I'll leave it up to you to implement containsFunctions() and clean up the code (infinite_loop_func as member function?) Note that with a counter, you could even deal with background task being spawned.
You can always use a specific exception type to signal to infinite_loop_func that it should return...
class quit_worker_exception: public std::exception {};
Then change infinite_loop_func to...
void infinite_loop_func ()
{
while (true) {
std::function<void()> func = func_pool.pop();
try {
func();
}
catch (quit_worker_exception &ex) {
return;
}
}
}
With the above changes you could then use (in main)...
/*
* Enqueue `thread_pool.size()' function objects whose sole job is
* to throw an instance of `quit_worker_exception' when invoked.
*/
for (int i = 0; i < thread_pool.size(); i++)
func_pool.push([](){ throw quit_worker_exception(); });
/*
* Now just wait for each worker to terminate having received its
* quit_worker_exception.
*/
for (int i = 0; i < thread_pool.size(); i++)
thread_pool.at(i).join();
Each instance of infinite_loop_func will dequeue one function object which, when called, throws a quit_worker_exception causing it to return.
Follwoing [JVApen](https://stackoverflow.com/posts/51382714/revisions) suggestion, I copy my code in case anyone will want a working code:
function_pool.h
#pragma once
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <cassert>
class Function_pool
{
private:
std::queue<std::function<void()>> m_function_queue;
std::mutex m_lock;
std::condition_variable m_data_condition;
std::atomic<bool> m_accept_functions;
public:
Function_pool();
~Function_pool();
void push(std::function<void()> func);
void done();
void infinite_loop_func();
};
function_pool.cpp
#include "function_pool.h"
Function_pool::Function_pool() : m_function_queue(), m_lock(), m_data_condition(), m_accept_functions(true)
{
}
Function_pool::~Function_pool()
{
}
void Function_pool::push(std::function<void()> func)
{
std::unique_lock<std::mutex> lock(m_lock);
m_function_queue.push(func);
// when we send the notification immediately, the consumer will try to get the lock , so unlock asap
lock.unlock();
m_data_condition.notify_one();
}
void Function_pool::done()
{
std::unique_lock<std::mutex> lock(m_lock);
m_accept_functions = false;
lock.unlock();
// when we send the notification immediately, the consumer will try to get the lock , so unlock asap
m_data_condition.notify_all();
//notify all waiting threads.
}
void Function_pool::infinite_loop_func()
{
std::function<void()> func;
while (true)
{
{
std::unique_lock<std::mutex> lock(m_lock);
m_data_condition.wait(lock, [this]() {return !m_function_queue.empty() || !m_accept_functions; });
if (!m_accept_functions && m_function_queue.empty())
{
//lock will be release automatically.
//finish the thread loop and let it join in the main thread.
return;
}
func = m_function_queue.front();
m_function_queue.pop();
//release the lock
}
func();
}
}
main.cpp
#include "function_pool.h"
#include <string>
#include <iostream>
#include <mutex>
#include <functional>
#include <thread>
#include <vector>
Function_pool func_pool;
class quit_worker_exception : public std::exception {};
void example_function()
{
std::cout << "bla" << std::endl;
}
int main()
{
std::cout << "stating operation" << std::endl;
int num_threads = std::thread::hardware_concurrency();
std::cout << "number of threads = " << num_threads << std::endl;
std::vector<std::thread> thread_pool;
for (int i = 0; i < num_threads; i++)
{
thread_pool.push_back(std::thread(&Function_pool::infinite_loop_func, &func_pool));
}
//here we should send our functions
for (int i = 0; i < 50; i++)
{
func_pool.push(example_function);
}
func_pool.done();
for (unsigned int i = 0; i < thread_pool.size(); i++)
{
thread_pool.at(i).join();
}
}
I wrote the following structure to implement a simple single producer / multi consumer synchronization. I'm using two integers available_index and consumed_index, access to consumed_index is protected by the condition variable cv. Here's the code:
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <thread>
struct ParserSync {
std::mutex worker_lock;
std::condition_variable cv;
int consumed_index = -1;
int available_index = -1;
bool exit_flag = false;
int consume_index() {
int ret = -1;
// get worker_lock
std::unique_lock<std::mutex> w_lock(worker_lock);
// wait for exit_flag or new available index
cv.wait(w_lock, [this] { return exit_flag || available_index > consumed_index; });
if (available_index > consumed_index) {
consumed_index++;
ret = consumed_index;
}
// Unlock mutex and notify another thread
w_lock.unlock();
cv.notify_one();
return ret;
}
void publish_index() {
available_index++;
std::cout << "before" << std::endl;
cv.notify_one();
std::cout << "after" << std::endl;
}
void set_exit() {
exit_flag = true;
cv.notify_all();
}
};
I tested my implementation using the following code (just a simple example to show the problem):
void producer(ParserSync &ps){
for (int i=0;i<5000;i++){
ps.publish_index();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
ps.set_exit();
std::cout << "Producer finished!" << std::endl;
}
void consumer(ParserSync &ps){
while (true){
int idx = ps.consume_index();
if (idx == -1)
break;
std::this_thread::sleep_for(std::chrono::milliseconds(4));
}
std::cout << "Consumer finished!" << std::endl;
}
int main() {
ParserSync ps{};
const int num_consumers = 4;
std::vector<std::thread> consumer_threads(num_consumers);
// start consumers
for (int i = 0; i < num_consumers; ++i) {
consumer_threads[i] = std::thread{consumer, std::ref(ps)};
}
// start producer
std::thread producer_thread = std::thread{producer, std::ref(ps)};
for (int i = 0; i < num_consumers; ++i) {
consumer_threads[i].join();
}
producer_thread.join();
std::cout << "Program finished" << std::endl;
return 0;
}
I would expect that producer thread produces 5000 indices and exits afterwards, but unfortunately, it gets stuck at some random iteration. I used print statements to find the code line that blocks and tracked it down to cv.notify_one();. This is the (shortened) console output:
...
before
after
before
after
before
Does anyone know why the call to cv.notify_one(); blocks?
I'm using MinGW (x86_64-6.2.0-posix-seh-rt_v5-rev1) on Windows 10.
Thanks in advance!
EDIT:
When compiling the exact same code with Visual Studio, the program works as expected and doesn't lock itself up. Unfortunately, I need to use MinGW for other reasons.
I'm creating 9 threads using something like this (all threads will process infinity loop)
void printStr();
thread func_thread(printStr);
void printStr() {
while (true) {
cout << "1\n";
this_thread::sleep_for(chrono::seconds(1));
}
}
I also create 10th thread to control them. How would I stop or kill any of this 9 threads from my 10th? Or suggest another mechanism please.
You can use, for example, atomic boolean:
#include <thread>
#include <iostream>
#include <vector>
#include <atomic>
using namespace std;
std::atomic<bool> run(true);
void foo()
{
while(run.load(memory_order_relaxed))
{
cout << "foo" << endl;
this_thread::sleep_for(chrono::seconds(1));
}
}
int main()
{
vector<thread> v;
for(int i = 0; i < 9; ++i)
v.push_back(std::thread(foo));
run.store(false, memory_order_relaxed);
for(auto& th : v)
th.join();
return 0;
}
EDIT (in response of your comment): you can also use a mutual variable, protected by a mutex.
#include <thread>
#include <iostream>
#include <vector>
#include <mutex>
using namespace std;
void foo(mutex& m, bool& b)
{
while(1)
{
cout << "foo" << endl;
this_thread::sleep_for(chrono::seconds(1));
lock_guard<mutex> l(m);
if(!b)
break;
}
}
void bar(mutex& m, bool& b)
{
lock_guard<mutex> l(m);
b = false;
}
int main()
{
vector<thread> v;
bool b = true;
mutex m;
for(int i = 0; i < 9; ++i)
v.push_back(thread(foo, ref(m), ref(b)));
v.push_back(thread(bar, ref(m), ref(b)));
for(auto& th : v)
th.join();
return 0;
}
It is never appropriate to kill a thread directly, you should instead send a signal to the thread to tell it to stop by itself. This will allow it to clean up and finish properly.
The mechanism you use is up to you and depends on the situation. It can be an event or a state checked periodically from within the thread.
std::thread objects are non - interruptible. You will have to use another thread library like boost or pthreads to accomplish your task. Please do note that killing threads is dangerous operation.
To illustrate how to approach this problem in pthread using cond_wait and cond_signal,In the main section you could create another thread called monitor thread that will keep waiting on a signal from one of the 9 thread.
pthread_mutex_t monMutex;////mutex
pthread_cond_t condMon;////condition variable
Creating threads:
pthread_t *threads = (pthread_t*) malloc (9* sizeof(pthread_t));
for (int t=0; t < 9;t++)
{
argPtr[t].threadId=t;
KillAll=false;
rc = pthread_create(&threads[t], NULL, &(launchInThread), (void *)&argPtr[t]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
creating monitor thread:
monitorThreadarg.threadArray=threads;//pass reference of thread array to monitor thread
monitorThreadarg.count=9;
pthread_t monitor_thread;
rc= pthread_create(&monitor_thread,NULL,&monitorHadle,(void * )(&monitorThreadArg));
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
then wait on 9 threads and monitor thread:
for (s=0; s < 9;s++)
{
pthread_join(threads[s], &status);
}
pthread_cond_signal(&condMon);// if all threads finished successfully then signal monitor thread too
pthread_join(monitor_thread, &status);
cout << "joined with monitor thread"<<endl;
The monitor function would be something like this:
void* monitorHadle(void* threadArray)
{
pthread_t* temp =static_cast<monitorThreadArg*> (threadArray)->threadArray;
int number =static_cast<monitorThreadArg*> (threadArray)->count;
pthread_mutex_lock(&monMutex);
mFlag=1;//check so that monitor threads has initialised
pthread_cond_wait(&condMon,&monMutex);// wait for signal
pthread_mutex_unlock(&monMutex);
void * status;
if (KillAll==true)
{
printf("kill all \n");
for (int i=0;i<number;i++)
{
pthread_cancel(temp[i]);
}
}
}
the function what will be launched over 9 threads should be something like this:
void launchInThread( void *data)
{
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(1)
{
try
{
throw("exception whenever your criteria is met");
}
catch (string x)
{
cout << "exception form !! "<< pthread_self() <<endl;
KillAll=true;
while(!mFlag);//wait till monitor thread has initialised
pthread_mutex_lock(&monMutex);
pthread_cond_signal(&condMon);//signail monitor thread
pthread_mutex_unlock(&monMutex);
pthread_exit((void*) 0);
}
}
}
Please note that if you dont't put :
thread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
after launching your thread then your threads wouldn't terminate on thread_cancel call.
It is necessary that you clean up up all the data before you cancel a thread.
The main() function creates a thread that is supposed to live until the user wishes to exit the program. The thread needs to return values to the main functions at periodic intervals. I tried doing something like this, but hasn't worked well -
std::queue<std::string> q;
void start_thread(int num)
{
std::string str;
//Do some processing
q.push(str);
}
int main()
{
//Thread initialization
int i;
//Start thread
pthread_create(&m_thread,NULL,start_thread,static_cast<void *>i);
while(true)
{
if(q.front())
{
std::cout<<q.front();
return 0;
}
}
//Destroy thread.....
return 0;
}
Any suggestions?
It is not safe to read and write from STL containers concurrently. You need a lock to synchronize access (see pthread_mutex_t).
Your thread pushes a single value into the queue. You seem to be expecting periodic values, so you'll want to modify start_thread to include a loop that calls queue.push.
The return 0; in the consumer loop will exit main() when it finds a value in the queue. You'll always read a single value and exit your program. You should remove that return.
Using if (q.front()) is not the way to test if your queue has values (front assumes at least one element exists). Try if (!q.empty()).
Your while(true) loop is gonna spin your processor somethin' nasty. You should look at condition variables to wait for values in the queue in a nice manner.
try locking a mutex before calling push() / front() on the queue.
Here is a working example of what it looks like you were trying to accomplish:
#include <iostream>
#include <queue>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
struct ThreadData
{
sem_t sem;
pthread_mutex_t mut;
std::queue<std::string> q;
};
void *start_thread(void *num)
{
ThreadData *td = reinterpret_cast<ThreadData *>(num);
std::vector<std::string> v;
std::vector<std::string>::iterator i;
// create some data
v.push_back("one");
v.push_back("two");
v.push_back("three");
v.push_back("four");
i = v.begin();
// pump strings out until no more data
while (i != v.end())
{
// lock the resource and put string in the queue
pthread_mutex_lock(&td->mut);
td->q.push(*i);
pthread_mutex_unlock(&td->mut);
// signal activity
sem_post(&td->sem);
sleep(1);
++i;
}
// signal activity
sem_post(&td->sem);
}
int main()
{
bool exitFlag = false;
pthread_t m_thread;
ThreadData td;
// initialize semaphore to empty
sem_init(&td.sem, 0, 0);
// initialize mutex
pthread_mutex_init(&td.mut, NULL);
//Start thread
if (pthread_create(&m_thread, NULL, start_thread, static_cast<void *>(&td)) != 0)
{
exitFlag = true;
}
while (!exitFlag)
{
if (sem_wait(&td.sem) == 0)
{
pthread_mutex_lock(&td.mut);
if (td.q.empty())
{
exitFlag = true;
}
else
{
std::cout << td.q.front() << std::endl;
td.q.pop();
}
pthread_mutex_unlock(&td.mut);
}
else
{
// something bad happened
exitFlag = true;
}
}
return 0;
}