My code acquires images and processes them. Performance is critical for my code, so I've tried my hand at multi-threading. Currently, I've only made the acquiring part a separate thread. I'm implementing a simple FIFO buffer using std::queue that stores the acquired images. The acquisition function AcquireImages writes raw image data to this buffer indefinitely until user interruption. Processing function, ProcessImages reads the buffer and processes the image data (currently in the main thread but I'm planning to make this a separate thread as well once I've ironed out issues). Here's my code (modified to form an MCV example):
#include <iostream>
#include <vector>
#include <queue>
#include <atomic>
#include <thread>
#define NUM_CAMERAS 2
void AcquireImages(std::queue<unsigned char*> &rawImageQueue, std::atomic<bool> &quit)
{
unsigned char* rawImage{};
while (!quit)
{
for (int camera = 0; camera < NUM_CAMERAS; camera++)
{
switch (camera)
{
case 0:
rawImage = (unsigned char*)"Cam0Image";
break;
case 1:
rawImage = (unsigned char*)"Cam1Image";
break;
default:
break;
}
rawImageQueue.push(std::move(rawImage));
}
}
}
int ProcessImages(const std::vector<unsigned char*> &rawImageVec, const int count)
{
// Do something to the raw image vector
if (count > 10)
{
return 1;
}
else
{
return 0;
} // In my application, this function only returns non-zero upon user interception.
}
int main()
{
// Preparation
std::vector<unsigned char*> rawImageVec;
rawImageVec.reserve(NUM_CAMERAS);
std::queue<unsigned char*> rawImageQueue;
int count{};
const unsigned int nThreads = 1; // this might grow later
std::atomic<bool> loopFlags[nThreads];
std::thread threads[nThreads];
// Start threads
for (int i = 0; i < nThreads; i++) {
loopFlags[i] = false;
threads[i] = std::thread(AcquireImages, rawImageQueue, ref(loopFlags[i]));
}
// Process images
while (true)
{
// Process the images
for (int cam{}; cam < NUM_CAMERAS; ++cam)
{
rawImageVec.push_back(rawImageQueue.front());
rawImageQueue.pop();
}
int processResult = ProcessImages(move(rawImageVec), count);
if (processResult)
{
std::cout << "Leaving while loop.\n"; // In my application this is triggered by the user
break;
}
rawImageVec.clear();
++count;
}
// Shutdown other threads
for (auto & flag : loopFlags) {
flag = true;
}
// Wait for threads to actually finish.
for (auto& thread : threads) {
thread.join();
}
return 0;
}
Some of you may have already noticed my blunder. What I know is that this program throws an exception atrawImageVec.push_back(rawImageQueue.front());.
The output after throwing the exception reads as follows:
Debug Assertion Failed!
Program: C:\WINDOWS\SYSTEM32\MSVCP140D.dll
File: c:\program files (x86)\microsoft visual studio 14.0\vc\include\deque
Line: 329
Expression: deque iterator not dereferencable
I understand the cause of the issue is probably that I'm reading something that is shared with another thread (Am I correct?). How do I resolve this?
I followed Praetorian's advice in the comments, after checking to see if rawImageQueue is empty, I see that it's always empty. I'm not sure what's causing this.
Here is a generalized example of producer/consumer on a shared queue. The idea is that if you're writing and reading from a data structure, you need some kind of protection around accesses.
For this, the below example uses condition variables and a mutex.
#include <thread>
#include <iostream>
#include <chrono>
#include <queue>
#include <mutex>
#include <vector>
#include <condition_variable>
using namespace std::chrono_literals;
using std::vector;
using std::thread;
using std::unique_lock;
using std::mutex;
using std::condition_variable;
using std::queue;
class WorkQueue
{
condition_variable work_available;
mutex work_mutex;
queue<int> work;
public:
void push_work(int item)
{
unique_lock<mutex> lock(work_mutex);
bool was_empty = work.empty();
work.push(item);
lock.unlock();
if (was_empty)
{
work_available.notify_one();
}
}
int wait_and_pop()
{
unique_lock<mutex> lock(work_mutex);
while (work.empty())
{
work_available.wait(lock);
}
int tmp = work.front();
work.pop();
return tmp;
}
};
int main() {
WorkQueue work_queue;
auto producer = [&]() {
while (true) {
work_queue.push_work(10);
std::this_thread::sleep_for(2ms);
}
};
vector<thread> producers;
producers.push_back(std::thread(producer));
producers.push_back(std::thread(producer));
producers.push_back(std::thread(producer));
producers.push_back(std::thread(producer));
std::thread consumer([&]() {
while (true)
{
int work_to_do = work_queue.wait_and_pop();
std::cout << "Got some work: " << work_to_do << std::endl;
}
});
std::for_each(producers.begin(), producers.end(), [](thread &p) {
p.join();
});
consumer.join();
}
Your case is relatively simple as seems you have just one producer and one consumer. Also image processing sounds quite slow (slow enough to not worry about threads contention) and you're switching from single-threaded version so probably no need to bother with highly efficient lock-free implementations.
I'd recommend to study this pseudo code: https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem#Using_monitors, then to learn about condition variables if you need: http://en.cppreference.com/w/cpp/thread/condition_variable.
Related
#include <iostream>
#include<thread>
#include <initializer_list>
#include <vector>
#include <future>
#include <time.h>
using namespace std;
class Gadget{
public:
Gadget(){
flag_ = false;
cout<<"Creating new Gadgets"<<endl;
}
void wait(){
while(flag_==false){
cout<<"waiting here...."<<endl;
this_thread::sleep_for(chrono::milliseconds(1000));
}
}
void wake(){
flag_ = true;
}
private:
volatile bool flag_;
};
I am trying to make two threads and one thread will sleep for 1 sec after checking the flag value. As i have made flag volatile it should change at some point. But the program is waiting infinitely.
int main() {
Gadget g;
thread t(&Gadget::wait,g);
thread s(&Gadget::wake,g);
t.join();
s.join();
cout<<"Ending the program "<<endl;
return 0;
}
volatile isn't for variables that are changed by the program itself. It's for variables that changes outside the program's control - like if it's directly connected to hardware.
Your main problem is however that you pass g by value so the two threads are working on different copies of your original g.
So, change to
std::atomic<bool> flag_;
and
thread t(&Gadget::wait, &g);
thread s(&Gadget::wake, &g);
Also worth mentioning: The two methods will not necessarily run in the order you start them, so waiting here.... may or may not show up.
Edit:
As mentioned in the comments: When waiting for a condition you should usually use a std::condition_variable. I've made an example of how that could look. I've also moved the starting of the threads into Gadget which makes it more obvious which object the thread is working on.
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
class Gadget {
public:
Gadget() { std::cout << "Creating new Gadget\n"; }
// new interface for starting threads
std::thread start_wait() { return std::thread(&Gadget::wait, this); }
std::thread start_wake() { return std::thread(&Gadget::wake, this); }
private:
void wait() {
std::unique_lock<std::mutex> ul(mutex_);
std::cout << "wait: waiting here...\n";
// Read about "spurious wakeup" to understand the below:
while(not flag_) cond_.wait(ul);
// or:
// cond_.wait(ul, [this] { return flag_; });
std::cout << "wait: done\n";
}
void wake() {
// simulate some work being done for awhile
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
{ // lock context start
std::lock_guard<std::mutex> lg(mutex_);
flag_ = true;
std::cout << "wake: notifying the waiting threads\n";
} // lock context end
// notify all waiting threads
cond_.notify_all();
}
std::condition_variable cond_;
std::mutex mutex_;
bool flag_ = false; // now guarded by a mutex instead
};
int main() {
Gadget g;
// start some waiting threads
std::vector<std::thread> threads(16);
for(auto& th : threads) th = g.start_wait();
// and one that wakes them up
auto th_wake = g.start_wake();
for(auto& th : threads) th.join();
th_wake.join();
std::cout << "Ending the program\n";
}
In my main program I am copying a string buffer into a boost ring buffer and then trying to consume that data in a created thread and writing to a file. In the main thread also I am writing the same data to a file but both input and output file is not matching.
I feel I am doing something incredibly stupid. Please help. Also, if there are any suggesting to improve the code that would really be appreciated.
#include <iostream>
#include <vector>
#include <boost/circular_buffer.hpp>
#include <numeric>
#include <assert.h>
#include <thread>
#include <mutex>
#include <chrono>
#include <time.h>
#include <cstdint>
#include <fstream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::fstream;
using std::string;
#define SOME_FIXED_HARDCODED_NUMBER 40980
class MyClass {
public:
std::vector<int8_t> vec;
public:
MyClass(std::vector<int8_t> v){ vec = v; }
};
boost::circular_buffer<MyClass> cb(300);
int waiting = 1;
std::mutex my_mutex;
FILE *out_file;
FILE *in_file;
void foo()
{
while (waiting) {
std::unique_lock<std::mutex> lock(my_mutex);
if (!cb.size() || waiting == 0) {
lock.unlock();
continue;
}
if (!waiting)
break;
MyClass local_buf = cb.front();
cb.pop_front();
fwrite(local_buf.vec.data(), 1, local_buf.vec.size(), out_file);
}
}
int main(int argc, char* argv[])
{
out_file = fopen("output_data.raw", "w");
in_file = fopen("input_data.raw", "w");
std::thread th1(foo);
char *buf = {"abc"};
int counter = 0;
std::vector<int8_t> mem;
mem.insert(mem.end(), buf, buf + strlen(buf));
while (counter < SOME_FIXED_HARDCODED_NUMBER)
{
{
std::unique_lock<std::mutex> lock(my_mutex);
/* if the circular buffer is full then wait for consumer to pull the data */
while (cb.full()) {
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::unique_lock<std::mutex> lock(my_mutex);
}
cb.push_front(MyClass(mem));
fwrite(mem.data(), 1, mem.size(), in_file);
}
counter++;
}
waiting = 0;
th1.join();
fclose(out_file);
fclose(in_file);
return 0;
}
while (cb.full()) {
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
>>> std::unique_lock<std::mutex> lock(my_mutex);
}
The marked unique_lock doesn't do anything as it will go out of scope immediately and unlock the mutex. Hence once you leave the loop the mutex is not locked and you have a racecondition. Instead, you should use lock.lock() to relock the mutex.
There is a few more bugs. You are not waiting for your foo thread to actually drain the buffer. It will stop as soon as the waiting flag is set by the main thread. Also, waiting should be an atomic.
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 am trying mutex lock with independent threads. The requirement is, I have many threads which will run independently and access/update a common recourse. To ensure that the recourse is updated via a single task, I used mutex. However this is not working.
I have pasted code, a representation of what I am trying to do below:
#include <iostream>
#include <map>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>
#include <unistd.h>
std::mutex mt;
static int iMem = 0;
int maxITr = 1000;
void renum()
{
// Ensure that only 1 task will update the variable
mt.lock();
int tmpMem = iMem;
usleep(100); // Make the system sleep/induce delay
iMem = tmpMem + 1;
mt.unlock();
printf("iMem = %d\n", iMem);
}
int main()
{
for (int i = 0; i < maxITr; i++) {
std::thread mth(renum);
mth.detach(); // Run each task in an independent thread
}
return 0;
}
but this is terminating with the below error:
terminate called after throwing an instance of 'std::system_error'
what(): Resource temporarily unavailable
I want to know if the usage of <thread>.detach() is correct above? If I use .join() it works, but I want each thread to run independently and not wait for the thread to finish.
I also want to know what is the best way to achieve the above logic.
Try this:
int main()
{
std::vector<std::thread> mths;
mths.reserve(maxITr);
for (int i = 0; i < maxITr; i++) {
mths.emplace_back(renum);
}
for (auto& mth : mths) {
mth.join();
}
}
This way, you retain control of the threads (by not calling detach()), and you can join them all at the end, so you know they have completed their tasks.
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;
}