Preface: this is my first attempt at writing a program in any language with multi-threading. I have no prior experience with std::thread, or with describing multi-threaded programs at all. Please let me know if you need more information to answer this question, or if I can reword anything to make my question clearer.
Suppose I have a simple animation function animate
, which (for now) runs indefinitely; and another function task
, which represents some arbitrary code to execute.
#include <string>
// a simple rotating stick animation: | -> / -> - -> \
void animate()
{
std::string syms = "|/-\\";
while (true)
{
for (unsigned int ii = 0; ii < syms.length(); ++ii)
{
std::cout << syms[ii];
std::cout << std::string(1, '\b');
}
}
}
// arbitrary function
void task()
{
// code to do something else goes here
}
int main (int argc, char* argv[])
{
// execute task and animate at the same time;
// return from animate once task has completed
return 0;
}
How can I use std::thread
(or some other header/library) to allow task
and animate
to communicate with each other, such that task
runs in the "background" and animate
runs until task
has completed?
I've taken your example code and tried to fill in the blanks from your intention with std::thread
. I've added some comments inline to explain what's going on. If something's not clear, or I got it wrong, feel free to ask in the comments.
I want to stress though that this example only uses std::thread
to create and join a separate thread in a toy example.
It does not synchronize shared data between threads in a correct way.
Shared data in MT environments is where things get hairy and the worst thing is that it can create some of the hardest to debug bugs out there. That's why the books and working examples are important for any substantial multithreaded program.
#include <string>
#include <thread>
#include <chrono>
#include <iostream>
// a simple rotating stick animation: | -> / -> - -> \
//
void animate(bool * should_animate)
{
// Using this namespace lets us use the "100ms" time literal in the sleep_for() function argument.
using namespace std::chrono_literals;
std::string syms = "|/-\\";
while (*should_animate)
{
for (unsigned int ii = 0; ii < syms.length(); ++ii)
{
std::cout << syms[ii];
std::cout << std::string(1, '\b');
// I had to flush cout so that the animation would show up
std::cout.flush();
// I added some delay here so that the animation is more visible
std::this_thread::sleep_for(100ms);
}
}
}
// arbitrary function
void task()
{
using namespace std::chrono_literals;
// I have this thread waiting for 2 seconds to simulate a lot of work being done
std::this_thread::sleep_for(2s);
}
int main (int argc, char* argv[])
{
// This line creates a thread from the animate() function
// The std::thread constructor is flexible, in that it can take a function with any number and type of arguments and
// make a thread out of it
// Once the thread is created, it gets sent to the operating system for scheduling right away in a separate thread
// I'm passing in a pointer to `should_animate` to use that value as a basic way to communicate to the animate thread to signal when it should stop running.
// I'm doing this to keep the example simple, but I stress that this isn't a good idea for larger scale programs
// Better to use propper signals or event queues
bool should_animate = true;
std::thread thread_animate(animate, &should_animate);
// This line creates a thread for the worker task
// That separate thread can be referenced by tis std::thread object
// Once the functions finish running, the thread associated with it is "joined"
std::thread thread_task(task);
// 'join' pauses the main thread to wait for the associated thread to finish running in the background.
thread_task.join();
// By this point in the program, the `task()` function has finished running, so we can flag
// the animate task to finish running so its thread can be joined
should_animate = false;
// Wait for the animate thread to get the message and finish
thread_animate.join();
std::cout << "Done!" << std::endl;
return 0;
}
If you want to take it a little further, here's some links I'd recommend.