How to synchronize data between threads - c++

This is my class to print data
class PrintData
{
int data[20];
public:
void setData(int dataValue[])
{
for( int i = 0 ; i < 20; i++)
data[i] = dataValue[i];
}
void Print()
{
for (int i = 0; i < 20; i++)
std::cout << data[i];
std::cout << std::endl;
}
};
This is the main function
int number[20] ;
void updateNumber()
{
for (int i = 0; i < 1000; i++) {
// std::this_thread::sleep_for(std::chrono::milliseconds(1000));
for (int k = 0; k < 20; k++)
number[k] = k;
// after one iteration it should wait and after the print.Print() is executed than it should again update the data
}
}
int main()
{
PrintData print;
std::thread t(&updateNumber);
while (true)
{
// if upDateNumber has updated all the numbers than only than only set the number
print.setData(number);
print.Print();
}
return 0;
}
After iteration has finished in the thread it should wait for the print.setData(number) function to execute , once this function has executed it should again update the data.
if print.setData(number) is called and the thread is still not finished updating the array than print.setData(number) should not update the data.

A simple example of a producer consumer problem involving conditional variables would be something like that:
#include <thread>
#include <mutex>
#include <iostream>
#include <condition_variable>
#include <vector>
#include <unistd.h>
#define MAX_SIZE 2
struct Task
{
std::condition_variable m_cond;
std::mutex m_lock;
Task(){}
};
std::vector<int> m_data;
Task m_producer;
Task m_consumers[MAX_SIZE];
std::mutex m_lock;
static bool s_Busy = false;
static void producer(void)
{
for(;;)
{
size_t input=0;
std::unique_lock<std::mutex> lock{m_lock};//{m_producer.m_lock};
if (!s_Busy) {
std::cout << "Enter a number: ";
std::cin >> input;
std::cout << "Producer waiting..." << std::this_thread::get_id() << "\r\n";
m_producer.m_cond.wait(lock);
}
s_Busy = true;
if (m_data.size() < input) {
for (size_t i=0; i < input; ++i){
m_data.push_back(i);
}
}
for (int i=0; i < MAX_SIZE; ++i) {
m_consumers[i].m_cond.notify_one();
}
lock.unlock();
}
}
static void consumers(void)
{
for(;;)
{
std::unique_lock<std::mutex> lock{m_lock};
if (!s_Busy) {
std::cout <<"Consumers waiting....!" << std::this_thread::get_id() << "\r\n";
for (int i=0; i < MAX_SIZE; ++i) {
m_consumers[i].m_cond.notify_all();
}
}
if (!m_data.empty()) {
std::cout << "Remove: " << m_data.at(0) << std::endl;
m_data.erase(m_data.begin());
usleep(1);
}
s_Busy = false;
m_producer.m_cond.notify_one();
lock.unlock();
}
}
int main()
{
std::vector<std::thread> cnsmrs;
std::thread usr{producer};
for (int i=0; i < MAX_SIZE; ++i)
cnsmrs.push_back(std::thread{consumers});
usr.join();
for(int i=0 ; i < MAX_SIZE; ++i)
cnsmrs.at(i).join();
return 0;
}
You can play with different logic and implementation.

I hope this help you: (semaphore is a self implementation of Qt's QSemaphore)
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
class semaphore
{
public:
semaphore(int n = 0) : m_n(n)
{
}
public:
void acquire(int n = 1)
{
std::unique_lock <std::mutex> lk(m_buf_mut);
while (m_n < n) {
m_cv.wait(lk);
}
m_n -= n;
}
void release(int n = 1)
{
{
std::unique_lock <std::mutex> lk(m_buf_mut);
m_n += n;
}
m_cv.notify_all();
}
bool tryAcquire(int n = 1)
{
std::unique_lock <std::mutex> lk(m_buf_mut);
if (m_n >= n) {
m_n -= n;
return true;
}
return false;
}
private:
std::mutex m_buf_mut;
int m_n;
std::condition_variable m_cv;
};
class PrintData
{
int data[20];
public:
void setData(int dataValue[])
{
for( int i = 0 ; i < 20; i++)
data[i] = dataValue[i];
}
void Print()
{
for (int i = 0; i < 20; i++)
std::cout << data[i];
std::cout << std::endl;
}
};
int number[20] ;
void updateNumber(semaphore *freeSem, semaphore *usedSem)
{
for (int i = 0; i < 1000; i++) {
// std::this_thread::sleep_for(std::chrono::milliseconds(1000));
//
freeSem->acquire();
for (int k = 0; k < 20; k++)
number[k] = k;
usedSem->release();
// after one iteration it should wait and after the print.Print() is executed than it should again update the data
}
}
int main()
{
PrintData print;
semaphore freeSem(1);
semaphore usedSem(0);
std::thread t(&updateNumber, &freeSem, &usedSem);
while (true)
{
// if upDateNumber has updated all the numbers than only than only set the number
usedSem.acquire();
print.setData(number);
print.Print();
freeSem.release();
}
return 0;
}

Related

How to make a function that can only be executed on one thread simultaneously?

I have a program that i am using to find prime numbers. it is executing on multiple threads. I am using the GetNextNumber() function for the threads to call to get a number to check if it is prime, however it seems that this function is being executed simultaneously by more than 1 thread, so sometimes two threads get the same number. here is my code:
#include "pch.h"
#include <cmath>
#include <fstream>
#include <thread>
#include <iostream>
#include <string>
int nextInt = 1;
std::ofstream file;
bool TestPrime(int number)
{
double rootInt = sqrt(number);
for (int i = 3; i <= rootInt; i += 2)
{
double divValue = (double)number / i;
if (int(divValue) == divValue)
{
return false;
}
}
return true;
}
int GetNextNumber()
{
return (nextInt += 2);
}
void PrimeFinderThread()
{
while (true)
{
int number = GetNextNumber();
bool isPrime = TestPrime(number);
if (isPrime)
{
std::string fileOutput = std::to_string(number) + "-";
file << fileOutput;
}
}
}
int main() {
file.open("primes.txt", std::ofstream::app);
file << 2 << "-";
std::thread threads[4];
for (int i = 0; i < 4; i++) {
threads[i] = std::thread(PrimeFinderThread);
}
for (int i = 0; i < 4; i++) {
threads[i].join();
}
return 0;
}
Using a mutex is a valid solution, but in this case it causes unnecessary overhead. You can simply make nextId atomic:
std::atomic<int> nextId{1};
This makes the increment operation in GetNextNumber atomic, so no two threads will get the same value.
Use a std::mutex with std::lock_guard. It will prevent simultaneous execution of the function.
#include "pch.h"
#include <cmath>
#include <fstream>
#include <thread>
#include <iostream>
#include <string>
#include <mutex>
int nextInt = 1;
std::ofstream file;
bool TestPrime(int number)
{
double rootInt = sqrt(number);
for (int i = 3; i <= rootInt; i += 2)
{
double divValue = (double)number / i;
if (int(divValue) == divValue)
{
return false;
}
}
return true;
}
int GetNextNumber()
{
static std::mutex m;
const std::lock_guard<std::mutex> lock(m);
return (nextInt += 2);
}
void PrimeFinderThread()
{
while (true)
{
int number = GetNextNumber();
bool isPrime = TestPrime(number);
if (isPrime)
{
std::string fileOutput = std::to_string(number) + "-";
file << fileOutput;
}
}
}
int main() {
file.open("primes.txt", std::ofstream::app);
file << 2 << "-";
std::thread threads[4];
for (int i = 0; i < 4; i++) {
threads[i] = std::thread(PrimeFinderThread);
}
for (int i = 0; i < 4; i++) {
threads[i].join();
}
return 0;
}

How do I correctly use std::mutex in C++ without deadlocks and/or races?

I am trying to debug a program that I am trying to run in parallel. I am at a loss for why I have both deadlocks and race conditions when I attempt to compile and run the code in C++. Here is all the relevant code that I have written thus far.
// define job struct here
// define mutex, condition variable, deque, and atomic here
std::deque<job> jobList;
std::mutex jobMutex;
std::condition_variable jobCondition;
std::atomic<int> numberThreadsRunning;
void addJobs(...insert parameters here...)
{
job current = {...insert parameters here...};
jobMutex.lock();
std::cout << "We have successfully acquired the mutex." << std::endl;
jobList.push_back(current);
jobCondition.notify_one();
jobMutex.unlock();
std::cout << "We have successfully unlocked the mutex." << std::endl;
}
void work(void) {
job* current;
numberThreadsRunning++;
while (true) {
std::unique_lock<std::mutex> lock(jobMutex);
if (jobList.empty()) {
numberThreadsRunning--;
jobCondition.wait(lock);
numberThreadsRunning++;
}
current = &jobList.at(0);
jobList.pop_front();
jobMutex.unlock();
std::cout << "We are now going to start a job." << std::endl;
////Call an expensive function for the current job that we want to run in parallel.
////This could either complete the job, or spawn more jobs, by calling addJobs.
////This recursive behavior typically results in there being thousands of jobs.
std::cout << "We have successfully completed a job." << std::endl;
}
numberThreadsRunning--;
std::cout << "There are now " << numberThreadsRunning << " threads running." << std::endl;
}
int main( int argc, char *argv[] ) {
//Initialize everything and add first job to the deque.
std::thread jobThreads[n]
for (int i = 0; i < n; i++) {
jobThreads[i] = std::thread(work);
}
for (int i = 0; i < n; i++) {
jobThreads[i].join();
}
}
The code compiles, but depending on random factors, it will either deadlock at the very end or have a segmentation fault in the middle while the queue is still quite large. Does anyone know more about why this is happening?
...
EDIT:
I have edited this question to include additional information and a more complete example. While I certainly don't want to bore you with the thousands of lines of code I actually have (an image rendering package), I believe this example better represents the type of problem I am facing. The example given in the answer by Alan Birtles only works on very simple job structure with very simple functionality. In the actual job struct, there are multiple pointers to different vectors and matrices, and therefore we need pointers to the job struct, otherwise the compiler would fail to compile because the constructor function was "implicitly deleted".
I believe the error I am facing has to do with the way I am locking and unlocking the threads. I know that the pointers are also causing some issues, but they probably have to stay. The function thisFunction() represents the function that needs to be run in parallel.
#include <queue>
#include <deque>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <iostream>
#include <cmath>
struct job {
std::vector<std::vector<int>> &matrix;
int num;
};
bool closed = false;
std::deque<job> jobList;
std::mutex jobMutex;
std::condition_variable jobCondition;
std::atomic<int> numberThreadsRunning;
std::atomic<int> numJobs;
struct tcout
{
tcout() :lock(mutex) {}
template < typename T >
tcout& operator<< (T&& t)
{
std::cout << t;
return *this;
}
static std::mutex mutex;
std::unique_lock< std::mutex > lock;
};
std::mutex tcout::mutex;
std::vector<std::vector<int>> multiply4x4(
std::vector<std::vector<int>> &A,
std::vector<std::vector<int>> &B) {
//Only deals with 4x4 matrices
std::vector<std::vector<int>> C(4, std::vector<int>(4, 0));
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 4; k++) {
C.at(i).at(j) = C.at(i).at(j) + A.at(i).at(k) * B.at(k).at(j);
}
}
}
return C;
}
void addJobs()
{
numJobs++;
std::vector<std::vector<int>> matrix(4, std::vector<int>(4, -1)); //Create random 4x4 matrix
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
matrix.at(i).at(j) = rand() % 10 + 1;
}
}
job current = { matrix, numJobs };
std::unique_lock<std::mutex> lock(jobMutex);
std::cout << "The matrix for job " << current.num << " is: \n";
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
std::cout << matrix.at(i).at(j) << "\t";
}
std::cout << "\n";
}
jobList.push_back(current);
jobCondition.notify_one();
lock.unlock();
}
void thisFunction(std::vector<std::vector<int>> &matrix, int num)
{
std::this_thread::sleep_for(std::chrono::milliseconds(rand() * 500 / RAND_MAX));
std::vector<std::vector<int>> product = matrix;
std::unique_lock<std::mutex> lk(jobMutex);
std::cout << "The imported matrix for job " << num << " is: \n";
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
std::cout << product.at(i).at(j) << "\t";
}
std::cout << "\n";
}
lk.unlock();
int power;
if (num % 2 == 1) {
power = 3;
} else if (num % 2 == 0) {
power = 2;
addJobs();
}
for (int k = 1; k < power; k++) {
product = multiply4x4(product, matrix);
}
std::unique_lock<std::mutex> lock(jobMutex);
std::cout << "The matrix for job " << num << " to the power of " << power << " is: \n";
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
std::cout << product.at(i).at(j) << "\t";
}
std::cout << "\n";
}
lock.unlock();
}
void work(void) {
job *current;
numberThreadsRunning++;
while (true) {
std::unique_lock<std::mutex> lock(jobMutex);
if (jobList.empty()) {
numberThreadsRunning--;
jobCondition.wait(lock, [] {return !jobList.empty() || closed; });
numberThreadsRunning++;
}
if (jobList.empty())
{
break;
}
current = &jobList.front();
job newcurrent = {current->matrix, current->num};
current = &newcurrent;
jobList.pop_front();
lock.unlock();
thisFunction(current->matrix, current->num);
tcout() << "job " << current->num << " complete\n";
}
numberThreadsRunning--;
}
int main(int argc, char *argv[]) {
const size_t n = 1;
numJobs = 0;
std::thread jobThreads[n];
std::vector<int> buffer;
for (int i = 0; i < n; i++) {
jobThreads[i] = std::thread(work);
}
for (int i = 0; i < 100; i++)
{
addJobs();
}
{
std::unique_lock<std::mutex> lock(jobMutex);
closed = true;
jobCondition.notify_all();
}
for (int i = 0; i < n; i++) {
jobThreads[i].join();
}
}
Here is a fully working example:
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <iostream>
struct job { int num; };
bool closed = false;
std::deque<job> jobList;
std::mutex jobMutex;
std::condition_variable jobCondition;
std::atomic<int> numberThreadsRunning;
struct tcout
{
tcout() :lock(mutex) {}
template < typename T >
tcout& operator<< (T&& t)
{
std::cout << t;
return *this;
}
static std::mutex mutex;
std::unique_lock< std::mutex > lock;
};
std::mutex tcout::mutex;
void addJobs()
{
static int num = 0;
job current = { num++ };
std::unique_lock<std::mutex> lock(jobMutex);
jobList.push_back(current);
jobCondition.notify_one();
lock.unlock();
}
void work(void) {
job current;
numberThreadsRunning++;
while (true) {
std::unique_lock<std::mutex> lock(jobMutex);
if (jobList.empty()) {
numberThreadsRunning--;
jobCondition.wait(lock, [] {return !jobList.empty() || closed; });
numberThreadsRunning++;
}
if (jobList.empty())
{
break;
}
current = jobList.front();
jobList.pop_front();
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(rand() * 500 / RAND_MAX));
tcout() << "job " << current.num << " complete\n";
}
numberThreadsRunning--;
}
int main(int argc, char *argv[]) {
const size_t n = 4;
std::thread jobThreads[n];
for (int i = 0; i < n; i++) {
jobThreads[i] = std::thread(work);
}
for (int i = 0; i < 100; i++)
{
addJobs();
}
{
std::unique_lock<std::mutex> lock(jobMutex);
closed = true;
jobCondition.notify_all();
}
for (int i = 0; i < n; i++) {
jobThreads[i].join();
}
}
I've made the following changes:
Never call lock() or unlock() on a std::mutex, always use std::unique_lock (or similar classes). You were calling jobMutex.unlock() in work() for the mutex you had locked with std::unique_lock, std::unique_lock would then call unlock for the second time leading to undefined behaviour. If an exception was thrown in addJobs then as you weren't using std::unique_lock at all the mutex would remain locked.
You need to use a predicate for jobCondition.wait otherwise a spurious wakeup could cause the wait to return while jobList is still empty.
I've added a closed variable to make the program exit when there's no more work to do
I've added a definition of job
In work you take a pointer to an item on the queue then pop it off the queue, as the item no longer exists the pointer is dangling. You need to copy the item before popping the queue. If you want to avoid the copy either make your job structure movable or change your queue to store std::unique_ptr<job> or std::shared_ptr<job>
I've also added a thread safe version of std::cout, this isn't strictly necessary but stops your output lines overlapping each other. Ideally you should use a proper thread safe logging library instead as locking a mutex for every print is expensive and if you have enough prints will make your program practically single threaded
Replace job* current; with job current; and then current = jobList.at(0);. Otherwise you end up with a pointer to an element of jobList that does not exist after jobList.pop_front().
Replace if (jobList.empty()) with while(jobList.empty()) to handle spurious wakeups.

Pipeline with thread vectors and queues C++

here is my code, it works but after few iterations it stop without any error, probably because of some race or deadlock.
The goal of the code is to model an encoding application: after the creation of some fake random frames, the stages of my pipeline are first give the type to the frames and than encode it with some random operation.
To do that I've used two different thread vectors (one for each stage) that are used concurrently with some shared queues, once one thread have pushed a frame, it is popped by another in the other vector and "encoded".
#include <iostream>
#include <vector>
#include <algorithm>
#include "SafeQueue.h"
using namespace std;
const int DATA_MAG = 256;
struct Frame
{
int num;
char type;
bool encoded;
vector<vector<int>> grid;
};
void do_join(thread& t)
{
t.join();
}
void join_all(vector<thread>& v)
{
for_each(v.begin(),v.end(),do_join);
}
void create_input (Queue<Frame>& stream, int num_frames, int height, int width)
{
for (int i = 0; i < num_frames; i++)
{
vector<vector<int>>tmp_grid(height, vector<int>(width, 0));
Frame frame;
for (int j = 0; j < height; j++)
{
for (int k = 0; k < width; k++)
{
tmp_grid[j][k] = rand()%DATA_MAG;
}
}
frame.grid = tmp_grid;
frame.num = i;
stream.push(frame);
}
}
void decide_type(int preset, Queue<Frame>& stream, Queue<Frame>& typed, vector<char>& param, int num_frames)
{
cout<<"hello from decide"<<" "<<endl;
for(int i = 0; i < num_frames; i++)
{
Frame tmp = stream.pop();
int j = rand() % 10;
if(j < preset)
{
tmp.type = 'I';
}
else
{
tmp.type = 'B';
}
param[tmp.num] = tmp.type;
typed.push(tmp);
}
}
void decode_flow(int preset, Queue<Frame>& typed, vector<Frame>& encoded,
vector<char>& parameters, int num_frames, int height, int width)
{
cout<<"hello from decode"<<" "<<endl;
for(int i = 0; i < num_frames; i++)
{
Frame f = typed.pop();
if (f.type == 'I')
{
cout<<"hi from I"<<" "<<endl;
for (int j = 0; j < height; j++)
{
for (int k = 0; k < width; k++)
{
f.grid[j][k] = f.grid[j][k] * 2;
}
}
}
else cout<<"hi from B"<<" "<<endl;
encoded.push_back(f);
}
}
int main()
{
srand(time(NULL));
int num_threadsXstage = 2;
int width = 500;
int height = 500;
int num_frames = 100;
int frames_thread = num_frames/num_threadsXstage;
int preset = 3;
vector<Frame> final;
//Vectors of threads
vector<thread> typer;
vector<thread> encoder;
//Vector of parameters
vector<char> parameters(num_frames);
//Working queues
Queue<Frame> created;
Queue<Frame> typed;
//Final vector
vector<Frame> encoded(num_frames);
//Movie creation
create_input(created, num_frames, height, width);
for (int i = 0; i < num_threadsXstage; i++)
{
//stage 1
typer.push_back(thread(bind(&decide_type, preset, ref(created),
ref(typed), ref(parameters), frames_thread)));
//stage 2
encoder.push_back(thread(bind(&decode_flow, preset, ref(typed), ref(encoded),
ref(parameters), frames_thread, height, width)));
}
// JOIN
join_all(typer);
join_all(encoder);
for (int i = 0; i < num_frames; i++)
{
Frame k = typed.pop();
cout<<k.type<<" ";
}
cout<<endl<<endl;
for (int i = 0; i < num_frames; i++)
{
cout<<parameters[i]<<" ";
}
}
And this is the code of my thread safe queue, or at least it is supposed to be.
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
using namespace std;
template <typename T>
class Queue
{
private:
queue<T> queue_;
mutex mutex_;
condition_variable cond_;
public:
T pop()
{
unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
auto val = queue_.front();
queue_.pop();
return val;
}
void pop(T& item)
{
unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
item = queue_.front();
queue_.pop();
}
void push(const T& item)
{
unique_lock<std::mutex> mlock(mutex_);
queue_.push(item);
mlock.unlock();
cond_.notify_one();
}
Queue()=default;
Queue(const Queue&) = delete; // disable copying
Queue& operator=(const Queue&) = delete; // disable assignment
};
After all threads have finished, you extract all the queued frames from the typed queue - but this is the intermediate queue between the processing stages, and is now empty. The call to typed.pop() will block forever.
You should be extracting the frames from the output queue encoded.

Implementation of a simple unit test for lock-free queue

I am trying to compare performance of different lock-free queues, therefore, I want to create a unit test - which includes pushing/poping user-defined pre-built objects to and from the queue. Therefore, I want to ask you couple of questions:-
1) How to create pre-built objects in a simple manner. Does creating an array like I did would fulfill the purpose.
2) I am getting an error "terminate called after throwing an instance of 'std::system_error' what(): Invalid argument Aborted (core dumped)".
Thanx in advance.
#include <cstdlib>
#include <stdio.h>
#include <string>
#include <chrono>
#include <iostream>
#include <ctime>
#include <atomic>
#include <thread>
#include <boost/lockfree/queue.hpp>
using namespace std;
const long NUM_DATA = 10;
const int NUM_PROD_THREAD = 2;
const int NUM_CONSUM_THREAD = 2;
const long NUM_ITEM = 1000000;
class Data
{
public:
Data(){}
void dataPrint() {cout << "Hello";}
private:
long i;
double j;
};
Data *DataArray = new Data[NUM_DATA];
boost::lockfree::queue<Data*> BoostQueue(1000);
struct Producer
{
void operator()()
{
for(long i=0; i<1000000; i++)
BoostQueue.push( DataArray );
}
};
struct Consumer
{
Data *pData;
void operator()()
{
while ( BoostQueue.pop( pData ) ) ;
}
};
int main(int argc, char** argv)
{
std::thread thrd [NUM_PROD_THREAD + NUM_CONSUM_THREAD];
std::chrono::duration<double> elapsed_seconds;
auto start = std::chrono::high_resolution_clock::now();
for ( int i = 0; i < NUM_PROD_THREAD; i++ )
{
thrd[i] = std::thread{ Producer() };
}
for ( int i = 0; i < NUM_CONSUM_THREAD; i++ )
{
thrd[NUM_PROD_THREAD+i] = std::thread{Consumer()};
}
for ( int i = 0; i < NUM_CONSUM_THREAD; i++ )
{
thrd[i].join();
}
auto end = std::chrono::high_resolution_clock::now();
elapsed_seconds = end - start;
std::cout << "Enqueue and Dequeue 1 million item in:" << elapsed_seconds.count() << std::endl;
for ( int i = 0; i < NUM_PROD_THREAD; i++ )
{
thrd[i].join();
}
return 0;
}
Just illustrating how to use Data elements in the benchmark, though this does add a cout within the measured time which isn't ideal but probably isn't significant either.
class Data
{
public:
Data(long i) : i_(i) {}
void dataPrint() {cout << "Hello";}
private:
long i_;
double j;
};
Data* dataArray[1000000];
for (int i = 0; i < NUM_DATA; ++i) dataArray[i] = new Data(i);
boost::lockfree::queue<Data*> BoostQueue(1000);
struct Producer
{
void operator()()
{
for(long i=0; i<1000000; i++)
BoostQueue.push( dataArray[i] );
}
};
struct Consumer
{
Data *pData;
long result_;
void operator()()
{
result_ = 0;
while ( BoostQueue.pop( pData ) )
result_ += pData->i_;
std::cout << result_ << '\n';
}
};
int main(int argc, char** argv)
{
std::thread thrd [NUM_PROD_THREAD + NUM_CONSUM_THREAD];
std::chrono::duration<double> elapsed_seconds;
auto start = std::chrono::high_resolution_clock::now();
for ( int i = 0; i < NUM_PROD_THREAD; i++ )
thrd[i] = std::thread{ Producer() };
for ( int i = 0; i < NUM_CONSUM_THREAD; i++ )
thrd[NUM_PROD_THREAD+i] = std::thread{Consumer()};
for ( int i = 0; i < NUM_CONSUM_THREAD; i++ )
thrd[NUM_PROD_THREAD+i].join();
auto end = std::chrono::high_resolution_clock::now();
elapsed_seconds = end - start;
std::cout << "Enqueue and Dequeue 1 million item in:"
<< elapsed_seconds.count() << std::endl;
for ( int i = 0; i < NUM_PROD_THREAD; i++ )
thrd[i].join();
for (int i = 0; i < 1000000; ++i)
delete dataArray[i];
}

Boost returning values from multithread vector

I am trying to develop a code which generates N threads into a loop. Each thread generates 40 random numbers and pick from them the highest. Afterwards, I have to choose the highest number from all. However, when I return the highest value of each thread (b) it is empty, this is the code I am using:
class rdm_thr
{
public:
rdm_thr()
{
}
void rdmgen()
{
default_random_engine generator;
double rdm;
b=0;
normal_distribution<double> normal(0, 1);
for(int i=0; i<40; i++)
{
rdm = normal(generator);
if(rdm>b)
b = rdm;
}
}
};
void main()
{
vector<boost::thread *> z;
vector<rdm_thr> o;
boost::function<void()> th_func;
for (int i = 0; i < 2; i++)
o.push_back(rdm_thr());
for (int i = 0; i < 2; i++)
{
th_func = boost::bind(&rdm_thr::rdmgen, &o[i]);
boost::thread thr(th_func);
z.push_back(&thr);
}
for (int i = 0; i < 2; i++)
{
z[i]->join();
}
}
Is there another way to do it?
You could change your class logic as such:
class rdm_thr
{
public:
rdm_thr() {}
void rdmgen()
{
...
}
void join() { t.join(); }
void start()
{
t = boost::thread(boost::bind(&rdm_thr::rdmgen, this));
}
private:
boost::thread t;
// could also be pointer type and 'new/delete' would have to be used in that event
};
#define TSZ 2
void main()
{
std::vector<rdm_thr*> o;
int i = 0;
for (; i < TSZ; i++) {
o.push_back(new rdm_thr());
o.back()->start();
}
for (i = 0; i < TSZ; i++) {
o[i]->join();
delete o[i]; //clean up
}
}
And if you didn't want to change your class logic, you could do the following in your main function:
#define TSZ 2
void main()
{
std::vector<boost::thread *> z;
std::vector<rdm_thr *> o;
int i = 0;
for (; i < TSZ; i++) {
o.push_back(new rdm_thr());
z.push_back(new boost::thread(boost::bind(&rdm_thr::rdmgen, o.back())));
}
for (i = 0; i < TSZ; i++) {
z[i]->join();
delete z[i];
delete o[i];
}
}
I don't have access to a compiler right now so I can't verify 100%, but as your asking more on theory, the above code is to help illustrate alternative ways of achieving similar results.
I hope that can help