I want to write a program in which many functions run simultaneously. I already figured out that in order to do that I need to use threads.
In my program a routine of heating and rotating an object with different temperatures and velocities has to run for a determined period of time in a loop. Once the time has passed I want the process to continue with my next heating/rotating (...). My idea was to write a "timer thread" that is able to end the current routine in some way, and skip to the next one. Is this possible?
I suppose most ways to do this are going to involve a shared flag between the working thread and the thread that signals it to stop working.
So you might have something along these lines:
// Use a std::atomic_bool to signal the thread safely
void process_stuff(std::atomic_bool& stop_processing)
{
while(!stop_processing) // do we keep going?
{
// do some measurements or action
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // wait for next action
}
}
Elsewhere in another thread ...
std::atomic_bool stop_processing{false};
// start thread (use std::ref() to pass by reference)
std::thread proc_thread(process_stuff, std::ref(stop_processing));
// wait for some time...
std::this_thread::sleep_for(std::chrono::seconds(3));
stop_processing = true; // signal end
proc_thread.join(); // wait for end to happen
// now create a new thread...
In the initiating thread, by changing the value of the variable stop_processing you signal the running thread to stop looping, in which case it ends gracefully.
Check this:
int main() {
// first thread
auto thread1 = std::make_unique<std::thread>([]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "over\n";
});
// disposing to second thread
std::thread([thread2 = std::move(thread1)](){
thread2->join();
}).detach();
//spinning a new thread
thread1.reset(new std::thread([]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "next over\n";
}));
thread1->join();
return 0;
}
Related
I am currently learning about Game Programming with the book 'Game Engine Architecture' authored by Jason Gregory.
In this book, he showed an example with the reason for using 'Condition Variable'
[Without Condition Variable]
Queue g_queue;
pthread_mutex_t g_mutex; bool
g_ready = false;
void* ProducerThread(void*)
{
// keep on producing forever...
while (true)
{
pthread_mutex_lock(&g_mutex);
// fill the queue with data
ProduceDataInto(&g_queue);
g_ready = true;
pthread_mutex_unlock(&g_mutex);
// yield the remainder of my timeslice
// to give the consumer a chance to run pthread_yield();
}
return nullptr;
}
void* ConsumerThread(void*)
{
// keep on consuming forever...
while (true)
{
// wait for the data to be ready
while (true)
{
// read the value into a local,
// making sure to lock the mutex
pthread_mutex_lock(&g_mutex);
const bool ready = g_ready;
pthread_mutex_unlock(&g_mutex);
if (ready) break;
}
// consume the data
pthread_mutex_lock(&g_mutex);
ConsumeDataFrom(&g_queue);
g_ready = false;
pthread_mutex_unlock(&g_mutex);
// yield the remainder of my timeslice
// to give the producer a chance to run pthread_yield();
}
return nullptr;
}
In this example, he said 'Besides the fact that this example is somewhat contrived, there’s one big problem with it: The consumer thread spins in a tight loop, polling the value of g_ready'
I found that the function 'pthread_mutex_lock(&g_mutex)' is a blocking function that if the calling thread can't acquire the mutex, it falls to asleep.
Then, isn't that the consumer thread is not on the state of 'busy-wait'?
I mean, doesn't it spin at all if it does not acquire the mutex?
Though pthread_mutex_lock is a blocking function, the producer and consumer loop will spin tightly. Because either ProduceDataInto or ConsumeDataFrom executed and returns immediately, the mutex repeats lock/unlock after each calling ProduceDataInto/ProduceDataInto.
So there must be a queue-full Condition Variable to make the producer wait and a queue-empty Condition Variable to make the consumer wait.
In modern C++ with STL threads I want to have two worker threads that take turns doing their work. Only one can be working at a time and each may only get one turn before the other takes a turn. I have this part working.
The added constraint is that one thread needs to keep taking turns after the other thread finishes. But in my code the remaining worker thread deadlocks after the first worker thread finishes. I don't understand why, given that the last things the first worker did was unlock and notify the condition variable, which should've woken the second one up. Here's the code:
{
std::mutex mu;
std::condition_variable cv;
int turn = 0;
auto thread_func = [&](int tid, int iters) {
std::unique_lock<std::mutex> lk(mu);
lk.unlock();
for (int i = 0; i < iters; i++) {
lk.lock();
cv.wait(lk, [&] {return turn == tid; });
printf("tid=%d turn=%d i=%d/%d\n", tid, turn, i, iters);
fflush(stdout);
turn = !turn;
lk.unlock();
cv.notify_all();
}
};
auto th0 = std::thread(thread_func, 0, 20);
auto th1 = std::thread(thread_func, 1, 25); // Does more iterations
printf("Made the threads.\n");
fflush(stdout);
th0.join();
th1.join();
printf("Both joined.\n");
fflush(stdout);
}
I don't know whether this is something I don't understand about concurrency in STL threads, or whether I just have a logic bug in my code. Note that there is a question on SO that's similar to this, but without the second worker having to run longer than the first. I can't find it right now to link to it. Thanks in advance for your help.
When one thread is done, the other will wait for a notification that nobody will send. When only one thread is left, you need to either stop using the condition variable or signal the condition variable some other way.
I'm having trouble instituting a timeout in one of my pthreads. I've simplified my code here and I've isolated the issue to be the CNF algorithm I'm running in the thread.
int main(){
pthread_t t1;
pthread_t t2;
pthread_t t3; //Running multiple threads, the others work fine and do not require a timeout.
pthread_create(&t1, nullptr, thread1, &args);
pthread_join(t1, nullptr);
std::cout << "Thread should exit and print this\n"; //This line never prints since from what I've figured to be a lack of cancellation points in the actual function running in the thread.
return 0;
}
void* to(void* args) {
int timeout{120};
int count{0};
while(count < timeout){
sleep(1);
count++;
}
std::cout << "Killing main thread" << std::endl;
pthread_cancel(*(pthread_t *)args);
}
void *thread1 (void *arguments){
//Create the timeout thread within the CNF thread to wait 2 minutes and then exit this whole thread
pthread_t time;
pthread_t cnf = pthread_self();
pthread_create(&time, nullptr, &timeout, &cnf);
//This part runs and prints that the thread has started
std::cout << "CNF running\n";
auto *args = (struct thread_args *) arguments;
int start = args->vertices;
int end = 1;
while (start >= end) {
//This is where the issue lies
cover = find_vertex_cover(args->vertices, start, args->edges_a, args->edges_b);
start--;
}
pthread_cancel(time); //If the algorithm executes in the required time then the timeout is not needed and that thread is cancelled.
std::cout << "CNF END\n";
return nullptr;
}
I tried commenting out the find_vertex_cover function and add an infinite loop and I was able to create a timeout and end the thread that way. The function is actually working the exact way it should. It should take forever to run under the conditions I'm running it at and therefore I need a timeout.
//This was a test thread function that I used to validate that implementing the timeout using `pthread_cancel()` this way works. The thread will exit once the timeout is reached.
void *thread1 (void *args) {
pthread_t x1;
pthread_t x2 = pthread_self();
pthread_create(&x1, nullptr, to, &x2);
/*
for (int i = 0;i<100; i++){
sleep(1);
std::cout << i << std::endl;
}
*/
}
Using this function I was able to validate that my timeout thread approach worked. The issue is when I actually run the CNF algorithm (using Minisat under the hood) once find_vertex_cover runs, there is no way to end the thread. The algorithm is expected to fail in the situation I'm implementing which is why a timeout is being implemented.
I've read up on using pthread_cancel() and while it isn't a great way it's the only way I could implement a timeout.
Any help on this issue would be appreciated.
I've read up on using pthread_cancel() and while it isn't a great way [..]
That's right. pthread_cancel should be avoided. It's especially bad for use in C++ as it's incompatible with exception handling. You should use std::thread and for thread termination, you can possibly use conditional variable or a atomic variable that terminates the "infinite loop" when set.
That aside, cancellation via pthread_cancel depends on two things: 1) cancellation state 2) cancellation type.
Default cancellation state is enabled. But the default cancellation type is deferred - meaning the cancellation request will be delivered only at the next cancellation point. I suspect there's any cancellation points in find_vertex_cover. So you could set the cancellation type to asynchronous via the call:
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
from the thread(s) you want to be able to cancel immediately.
But again, I suggest to not go for pthread_cancel approach at all and instead rewrite the "cancel" logic so that it doesn't involve pthread_cancel.
I am a complete beginner with threads therefore I'm not able to resolve this problem myself.
I have two threads which should run in parallel. The first thread should read in the data (simulate receive queue thread) and once data is ready the second thread shall process (processing thread) the data. The problem is, that the second thread will wait for a change of the conditional variable an infinite amount of time.
If I remove the for loop of the first thread, conditional variable will notify the second thread but the thread will only execute once. Why is the conditional variable not notified if it is used within the for loop?
My goal is to read in all data of a CSV file in the first thread and store it dependent on the rows content in a vector in the second thread.
Thread one look like this
std::mutex mtx;
std::condition_variable condVar;
bool event_angekommen{false};
void simulate_event_readin(CSVLeser leser, int sekunden, std::vector<std::string> &csv_reihe)
{
std::lock_guard<std::mutex> lck(mtx);
std::vector<std::vector<std::string>> csv_daten = leser.erhalteDatenobj();
for (size_t idx = 1; idx < csv_daten.size(); idx++)
{
std::this_thread::sleep_for(std::chrono::seconds(sekunden));
csv_reihe = csv_daten[idx];
event_angekommen = true;
condVar.notify_one();
}
}
Thread two looks like this:
void detektiere_events(Detektion detektion, std::vector<std::string> &csv_reihe, std::vector<std::string> &pir_events)
{
while(1)
{
std::cout<<"Warte"<<std::endl;
std::unique_lock<std::mutex> lck(mtx);
condVar.wait(lck, [] {return event_angekommen; });
std::cout<<"Detektiere Events"<<std::endl;
std::string externes_event_user_id = csv_reihe[4];
std::string externes_event_data = csv_reihe[6];
detektion.neues_event(externes_event_data, externes_event_user_id);
if(detektion.pruefe_Pir_id() == true)
{
pir_events.push_back(externes_event_data);
};
}
}
and my main looks like this:
int main(void)
{
Detektion detektion;
CSVLeser leser("../../Example Data/collectedData_Protocol1.csv", ";");
std::vector<std::string> csv_reihe;
std::vector<std::string> pir_values = {"28161","28211","28261","28461","285612"};
std::vector<std::string> pir_events;
std::thread thread[2];
thread[0] = std::thread(simulate_event_readin, leser, 4, std::ref(csv_reihe));
thread[1] = std::thread(detektiere_events,detektion, std::ref(csv_reihe), std::ref(pir_events));
thread[0].join();
thread[1].join();
}
I'm not a C++ expert, but the code seems understandable enough to see the issue.
Your thread 1 grabs the lock once and doesn't release it until the end of its lifetime. It may signal that the condition is fulfilled, but it never actually releases the lock to allow other threads to act.
To fix this, move std::lock_guard<std::mutex> lck(mtx); inside the loop, after sleeping. This way, the thread will take and release the lock on each iteration, giving the other thread an opportunity to act while sleeping.
Assuming I have the function double someRandomFunction(int n) that takes an integer and returns double but it's random in the sense that it tries random stuff to come up with the solution so even though you run the function with the same arguments, sometimes it can take 10 seconds to finish and other 40 seconds to finish.
The double someRandomFunction(int n) functions itself is a wrapper to a black box function. So the someRandomFunction takes a while to complete but I don't have control in the main loop of the black box, hence I can't really check for a flag variable within the thread as the heavy computation happens in a black box function.
I would like to start 10 threads calling that function and I am interested in the result of the first thread which finishes first. I don't care which one it's I only need 1 result from these threads.
I found the following code:
std::vector<boost::future<double>> futures;
for (...) {
auto fut = boost::async([i]() { return someRandomFunction(2) });
futures.push_back(std::move(fut));
}
for (...) {
auto res = boost::wait_for_any(futures.begin(), futures.end());
std::this_thread::yield();
std::cout << res->get() << std::endl;
}
Which is the closest to what I am looking for, but still I can't see how I can make my program to terminate the other threads as far as one thread returns a solution.
I would like to wait for one to finish and then carry on with the result of that one thread to continue my program execution (i.e., I don't want to terminate my program after I obtain that single result, but I would like to use it for the remaining program execution.).
Again, I want to start up 10 threads calling the someRandomFunction and then wait for one thread to finish first, get the result of that thread and stop all the other threads even though they didn't finish their work.
If the data structure supplied to the black-box has some obvious start and end values, one way to make it finish early could be to change the end value while it's computing. It could of course cause all sorts of trouble if you've misunderstood how the black-box must work with the data, but if you are reasonably sure, it can work.
main spawns 100 outer threads that each spawn one inner thread that calls the blackbox. The inner thread receives the blackbox result and notifies all waiting threads that it's done. The outer thread waits for any inner thread to get done and then modifies the data for its own blackbox to trick it to finish.
No polling (except for the spurious wakeup loops) and no detached threads.
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <chrono>
// a work package for one black-box
struct data_for_back_box {
int start_here;
int end_here;
};
double blackbox(data_for_back_box* data) {
// time consuming work here:
for(auto v=data->start_here; v<data->end_here; ++v) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
// just a debug
if(data->end_here==0) std::cout << "I was tricked into exiting early\n";
return data->end_here;
}
// synchronizing stuff and result
std::condition_variable cv;
std::mutex mtx;
bool done=false;
double result;
// a wrapper around the real blackbox
void inner(data_for_back_box* data) {
double r = blackbox(data);
if(done) return; // someone has already finished, skip this result
// notify everyone that we're done
std::unique_lock<std::mutex> lock(mtx);
result = r;
done=true;
cv.notify_all();
}
// context setup and wait for any inner wrapper
// to signal "done"
void outer(int n) {
data_for_back_box data{0, 100+n*n};
std::thread work(inner, &data);
{
std::unique_lock<std::mutex> lock(mtx);
while( !done ) cv.wait(lock);
}
// corrupt data for blackbox:
data.end_here = 0;
// wait for this threads blackbox to finish
work.join();
}
int main() {
std::vector<std::thread> ths;
// spawn 100 worker threads
for(int i=0; i<100; ++i) {
ths.emplace_back(outer, i);
}
double saved_result;
{
std::unique_lock<std::mutex> lock(mtx);
while( !done ) cv.wait(lock);
saved_result = result;
} // release lock
// join all threads
std::cout << "got result, joining:\n";
for(auto& th : ths) {
th.join();
}
std::cout << "result: " << saved_result << "\n";
}