Multiple consumer and producers, how do I unlock consumer thread - multithreading

I am trying to make a multiple producer and consumer program. The producers produce random numbers and insert them into a shared queue(shared memory) and the consumers print out the numbers. The user calls the program with the following arguments: number of producer threads, number of consumer threads and the size of the shared data.
Right now it just produces one producer(it seems) and just stops. I wanted to see if I can get some help figuring out how to unlock the consumers.
This is the Queue header
class SyncQueue
{
public:
SyncQueue(int sizeMax);
void enqueue(int value);
int dequeue();
private:
int MaxSize, front, rear, itemcounter;
std::vector<int> QueueElements;
std::mutex mutex;
//Condition variables for full and empty checks
std::condition_variable NotFull;
std::condition_variable NotEmpty;
};
This is the Queue functions
SyncQueue::SyncQueue(int sizeMax)
{
front = 0;
rear = 0;
MaxSize = sizeMax;
itemcounter = 0;
QueueElements.reserve(MaxSize);
}
void SyncQueue::enqueue(int value)
{
std::unique_lock<std::mutex> lock(mutex);
NotFull.wait(lock , [this](){return itemcounter != MaxSize; });
QueueElements[rear] = value;
rear = (rear + 1) % MaxSize;
++itemcounter;
NotEmpty.notify_all();
}
int SyncQueue::dequeue()
{
std::unique_lock<std::mutex> lock(mutex);
NotEmpty.wait(lock, [this](){return itemcounter != 0; });
int number = QueueElements[front];
front = (front + 1) % MaxSize;
--itemcounter;
NotFull.notify_all();
return number;
}
This is main where I create the threads
std::vector<std::thread> producers(producerThreadCount);
std::vector<std::thread> consumers(consumerThreadCount);
SyncQueue queue(size);
//Build producer threads
for (int i = 0; i < producerThreadCount; i++)
{
producers[i] = std::thread(produceThread, i,std::ref(ProducerMutex), std::ref(queue), 200);
}
//Build consumers
for (int i = 0; i < consumerThreadCount; i++)
{
consumers[i] = std::thread(consumeThread, i, std::ref(ConsumerMutex), std::ref(queue), 400);
}
These are the produce and consume threads
void produceThread(int threadId, std::mutex &ProducerMutex, SyncQueue &sharedQueue, int time)
{
while (true)
{
int value = RandomNumberGenerator(std::ref(ProducerMutex));
sharedQueue.enqueue(value);
std::this_thread::sleep_for(std::chrono::milliseconds(time));
}
}
void consumeThread(int threadId, std::mutex &ConsumerMutex, SyncQueue &sharedQueue, int time)
{
while (true)
{
std::lock_guard<std::mutex> lock(ConsumerMutex);
int value;
std::cout << "Thread:" << threadId << " consumes:" <<sharedQueue.dequeue() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(time));
}
}

Related

operating issues qustions - threads, processes etc. for the above code:

int S1 = 0;
int S2 = 0;
int x = 0;
int run = 1;
void Producer(void) {
while(run) {
while (S1 == S2);
x++;
__sync_synchronize();
S1 = S2;
__sync_synchronize();
}
}
void Consumer(void) {
while(run) {
while (S1 != S2);
x--;
__sync_synchronize();
S1 = !S2;
__sync_synchronize();
}
}
void* Worker(void *func) {
long func_id = (long)func & 0x1;
printf("%s %d\n",__func__, (int)func_id);
switch (func_id) {
case 0:
Producer();
break;
case 1:
Consumer();
break;
}
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t t[argc];
pthread_attr_t at;
cpu_set_t cpuset;
int threads;
int i;
#define MAX_PROCESSORS 4 // Minimal processors is 2.
threads = argc > 1 ? (( atoi(argv[1]) < 4) ? atoi(argv[1]): MAX_PROCESSORS ) : 1;
for (i = 0;i < threads; i++){
CPU_ZERO(&cpuset);
CPU_SET(i, &cpuset);
pthread_attr_init(&at);
(&at, sizeof(cpuset), &cpuset);
if (pthread_create(&t[i], &at , Worker, (void *) (long)i) ) {
perror("pthread create 1 error\n"); }
}
do {
sleep(1);
} while(x < 0);
run = 0;
void *val;
for(i = 0; i < threads; i++)
pthread_join(t[i], &val);
printf("x=%d\n", x);
}
The questions:
In ex1.c (6.1), which of the following properties achieved:
(1) Mutual exclusion but not progress
(2) Progress but not mutual exclusion
(3) Neither mutual exclusion nor progress
(4) Both mutual exclusion and progress
Please explain?
1.2
To which arguments (in 6.1) is correct and which does not:
(1) always exits. when threads = 2 or threads <= 0
(2) always hangs. threads = 1 or thread > 2
Any help would be much appreeciated

How to prematurely kill std::async threads before they are finished *without* using a std::atomic_bool?

I have a function that takes a callback, and used it to do work on 10 separate threads. However, it is often the case that not all of the work is needed. For example, if the desired result is obtained on the third thread, it should stop all work being done on of the remaining alive threads.
This answer here suggests that it is not possible unless you have the callback functions take an additional std::atomic_bool argument, that signals whether the function should terminate prematurely.
This solution does not work for me. The workers are spun up inside a base class, and the whole point of this base class is to abstract away details of multithreading. How can I do this? I am anticipating that I will have to ditch std::async for something more involved.
#include <iostream>
#include <future>
#include <vector>
class ABC{
public:
std::vector<std::future<int> > m_results;
ABC() {};
~ABC(){};
virtual int callback(int a) = 0;
void doStuffWithCallBack();
};
void ABC::doStuffWithCallBack(){
// start working
for(int i = 0; i < 10; ++i)
m_results.push_back(std::async(&ABC::callback, this, i));
// analyze results and cancel all threads when you get the 1
for(int j = 0; j < 10; ++j){
double foo = m_results[j].get();
if ( foo == 1){
break; // but threads continue running
}
}
std::cout << m_results[9].get() << " <- this shouldn't have ever been computed\n";
}
class Derived : public ABC {
public:
Derived() : ABC() {};
~Derived() {};
int callback(int a){
std::cout << a << "!\n";
if (a == 3)
return 1;
else
return 0;
};
};
int main(int argc, char **argv)
{
Derived myObj;
myObj.doStuffWithCallBack();
return 0;
}
I'll just say that this should probably not be a part of a 'normal' program, since it could leak resources and/or leave your program in an unstable state, but in the interest of science...
If you have control of the thread loop, and you don't mind using platform features, you could inject an exception into the thread. With posix you can use signals for this, on Windows you would have to use SetThreadContext(). Though the exception will generally unwind the stack and call destructors, your thread may be in a system call or other 'non-exception safe place' when the exception occurs.
Disclaimer: I only have Linux at the moment, so I did not test the Windows code.
#if defined(_WIN32)
# define ITS_WINDOWS
#else
# define ITS_POSIX
#endif
#if defined(ITS_POSIX)
#include <signal.h>
#endif
void throw_exception() throw(std::string())
{
throw std::string();
}
void init_exceptions()
{
volatile int i = 0;
if (i)
throw_exception();
}
bool abort_thread(std::thread &t)
{
#if defined(ITS_WINDOWS)
bool bSuccess = false;
HANDLE h = t.native_handle();
if (INVALID_HANDLE_VALUE == h)
return false;
if (INFINITE == SuspendThread(h))
return false;
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_CONTROL;
if (GetThreadContext(h, &ctx))
{
#if defined( _WIN64 )
ctx.Rip = (DWORD)(DWORD_PTR)throw_exception;
#else
ctx.Eip = (DWORD)(DWORD_PTR)throw_exception;
#endif
bSuccess = SetThreadContext(h, &ctx) ? true : false;
}
ResumeThread(h);
return bSuccess;
#elif defined(ITS_POSIX)
pthread_kill(t.native_handle(), SIGUSR2);
#endif
return false;
}
#if defined(ITS_POSIX)
void worker_thread_sig(int sig)
{
if(SIGUSR2 == sig)
throw std::string();
}
#endif
void init_threads()
{
#if defined(ITS_POSIX)
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = worker_thread_sig;
sigaction(SIGUSR2, &sa, 0);
#endif
}
class tracker
{
public:
tracker() { printf("tracker()\n"); }
~tracker() { printf("~tracker()\n"); }
};
int main(int argc, char *argv[])
{
init_threads();
printf("main: starting thread...\n");
std::thread t([]()
{
try
{
tracker a;
init_exceptions();
printf("thread: started...\n");
std::this_thread::sleep_for(std::chrono::minutes(1000));
printf("thread: stopping...\n");
}
catch(std::string s)
{
printf("thread: exception caught...\n");
}
});
printf("main: sleeping...\n");
std::this_thread::sleep_for(std::chrono::seconds(2));
printf("main: aborting...\n");
abort_thread(t);
printf("main: joining...\n");
t.join();
printf("main: exiting...\n");
return 0;
}
Output:
main: starting thread...
main: sleeping...
tracker()
thread: started...
main: aborting...
main: joining...
~tracker()
thread: exception caught...
main: exiting...

Thread notification isn't working for my consumer

I have an attempt at a producer/consumer
Producer
#pragma once
#ifndef PRODUCER_H
#define PRODUCER_H
#include <thread>
#include "Mailbox.h"
class Producer
{
private:
std::thread producer;
Mailbox& mailbox;
public:
Producer(Mailbox& newmailbox);
~Producer();
void start();
void run();
};
Producer::Producer(Mailbox& newMailbox) : mailbox(newMailbox) {}
Producer::~Producer() {}
void Producer::start()
{
producer = std::thread(&Producer::run, this);
}
void Producer::run()
{
mailbox.inc();
}
#endif
Consumer
#pragma once
#ifndef CONSUMER_H
#define CONSUMER_H
#include "Mailbox.h"
#include <thread>
#include <iostream>
class Consumer
{
private:
Mailbox& mailbox;
std::thread consumer;
public:
Consumer(Mailbox& newMailbox);
~Consumer();
void start();
void run();
};
Consumer::Consumer(Mailbox& newMailbox) : mailbox(newMailbox) {}
Consumer::~Consumer() {}
void Consumer::start()
{
consumer = std::thread(&Consumer::run, this);
}
void Consumer::run()
{
mailbox.read();
}
#endif
Mailbox
#pragma once
#ifndef MAILBOX_H
#define MAILBOX_H
#include <mutex>
#include <iostream>
class Mailbox
{
private:
int& mailbox;
int init_val;
std::mutex mmutex;
std::condition_variable condition;
public:
Mailbox();
~Mailbox();
void inc();
void read();
};
Mailbox::Mailbox() : mailbox(init_val), init_val(0) {}
Mailbox::~Mailbox()
{
}
void Mailbox::inc()
{
int count = 0;
while (count < 10)
{
std::unique_lock<std::mutex> lock(mmutex);
std::cout << "Producer increment\n";
mailbox += 1;
lock.unlock();
count += 1;
}
}
void Mailbox::read()
{
int count = 0;
while (count < 10)
{
std::unique_lock<std::mutex> lock(mmutex);
condition.wait(lock, [this](){return get_cflag(); });
condition.notify_one();
count += 1;
}
}
#endif
Main
int main()
{
Mailbox* mailbox = new Mailbox();
Consumer* consumer = new Consumer(*mailbox);
Producer* producer = new Producer(*mailbox);
consumer->start();
producer->start();
return 0;
}
Mutex locking works albeit asynchronously because I have no control over when a std::thread will start so I decided to implement a semi-synchronous methodology using std::unique_lock in addition to std::mutex.
Problem is, the Consumer waits and the Producer flies on ahead with no notification at least that is what the debugger is telling me and the last Producer iteration result sin a n abort() so something is going wrong here.
Based upon David Schwartz's comment, insight from Mike Strobel, and additional research, I changed the producer and consumer functions
Producer
void Mailbox::inc()
{
int count = 0;
while (count < 10)
{
std::unique_lock<std::mutex> lock(mmutex);
std::cout << "Producer increment\n";
mailbox += 1;
lock.unlock();
set_cflag(true); // signal to the consumer data is ready
condition.notify_one();
{
std::unique_lock<std::mutex> lock(mmutex);
condition.wait(lock, [this]() {return get_pflag(); });
}
set_pflag(false);
count += 1;
}
}
Consumer
void Mailbox::read()
{
int count = 0;
while (count < 10)
{
std::unique_lock<std::mutex> lock(mmutex);
condition.wait(lock, [this](){return get_cflag(); });
std::cout << "Consumer: " << mailbox << "\n";
lock.unlock();
set_pflag(true);
condition.notify_one();
count += 1;
set_cflag(false);
}
}
Mailbox
class Mailbox
{
private:
int& mailbox;
int cflag, pflag;
int init_val;
std::mutex mmutex;
std::condition_variable condition;
public:
Mailbox();
~Mailbox();
int get_cflag() { return cflag; }
void set_cflag(int newFlag) { cflag = newFlag; }
int get_pflag() { return pflag; }
void set_pflag(int newFlag) { pflag = newFlag; }
void inc();
void read();
};
Mailbox::Mailbox() : mailbox(init_val), init_val(0), cflag(0), pflag(0) {}
Mailbox::~Mailbox()
{
}
The output upon execution is as I desired
int main()
{
Mailbox* mailbox = new Mailbox();
Consumer* consumer = new Consumer(*mailbox);
Producer* producer = new Producer(*mailbox);
consumer->start();
producer->start();
fgetc(stdin);
return 0;
}
Producer increment
Consumer: 1
Producer increment
Consumer: 2
Producer increment
Consumer: 3
Producer increment
Consumer: 4
Producer increment
Consumer: 5
Producer increment
Consumer: 6
Producer increment
Consumer: 7
Producer increment
Consumer: 8
Producer increment
Consumer: 9
Producer increment
Consumer: 10
I’m not a C++ guy, but if these condition variables work the way I think they do, you’ll only get notified if a signal arrives while you’re waiting. If the signal arrived before you started waiting, you’ll block indefinitely.
After you acquire the lock in 'Mailbox::read`, you should check to see if an item is available, and only wait on the condition variable if there isn’t one. If there is, go ahead and take it:
int Mailbox::read()
{
std::unique_lock<std::mutex> lock(m);
while (mailbox <= 0)
condition.wait(lock);
return mailbox--;
}

C++11 condtional variable

I am trying make a lot of mistakes to learn Concurrency in C++11. I have to ask this,
Here is what this one is supposed to do:
One queue, and three threads, one is suppose to put an integer into the queue, the other twos are suppose to correspondingly increase s1, s2 by popping the queue so that I can get total sum of numbers that were in the queue. To make it simpler I put 1 through 10 numbers into the queue.
But sometimes it works and sometimes it seems like there is an infinite loop:: what would be the reason?
#include <queue>
#include <memory>
#include <mutex>
#include <thread>
#include <iostream>
#include <condition_variable>
#include <string>
class threadsafe_queue {
private:
mutable std::mutex mut;
std::queue<int> data_queue;
std::condition_variable data_cond;
std::string log; //just to see what is going on behind
bool done;
public:
threadsafe_queue(){
log = "initializing queue\n";
done = false;
}
threadsafe_queue(threadsafe_queue const& other) {
std::lock_guard<std::mutex> lk(other.mut);
data_queue = other.data_queue;
}
void set_done(bool const s) {
std::lock_guard<std::mutex> lk(mut);
done = s;
}
bool get_done() {
std::lock_guard<std::mutex> lk(mut);
return done;
}
void push(int new_value) {
std::lock_guard<std::mutex> lk(mut);
log += "+pushing " + std::to_string(new_value) + "\n";
data_queue.push(new_value);
data_cond.notify_one();
}
void wait_and_pop(int& value) {
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty();});
value = data_queue.front();
log += "-poping " + std::to_string(value) + "\n";
data_queue.pop();
}
std::shared_ptr<int> wait_and_pop() {
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty();});
std::shared_ptr<int> res(std::make_shared<int>(data_queue.front()));
log += "- popping " + std::to_string(*res) + "\n";
data_queue.pop();
return res;
}
bool try_pop(int& value) {
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty()) {
log += "tried to pop but it was empty\n";
return false;
}
value = data_queue.front();
log += "-popping " + std::to_string(value) + "\n";
data_queue.pop();
return true;
}
std::shared_ptr<int> try_pop() {
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty()) {
log += "tried to pop but it was empty\n";
return std::shared_ptr<int>();
}
std::shared_ptr<int> res(std::make_shared<int>(data_queue.front()));
log += "-popping " + std::to_string(*res) + "\n";
data_queue.pop();
return res;
}
bool empty() const {
std::lock_guard<std::mutex> lk(mut);
//log += "checking the queue if it is empty\n";
return data_queue.empty();
}
std::string get_log() {
return log;
}
};
threadsafe_queue tq;
int s1, s2;
void prepare() {
for (int i = 1; i <= 10; i++)
tq.push(i);
tq.set_done(true);
}
void p1() {
while (true) {
int data;
tq.wait_and_pop(data);
s1 += data;
if (tq.get_done() && tq.empty()) break;
}
}
void p2() {
while (true) {
int data;
tq.wait_and_pop(data);
s2 += data;
if (tq.get_done() && tq.empty()) break;
}
}
int main(int argc, char *argv[]) {
std::thread pp(prepare);
std::thread worker(p1);
std::thread worker2(p2);
pp.join();
worker.join();
worker2.join();
std::cout << tq.get_log() << std::endl;
std::cout << s1 << " " << s2 << std::endl;
return 0;
}
Look at function p1 line 5
if (tq.get_done() && tq.empty()) break;
So you checked the queue if it was empty. It was not. Now you loop and enter
tq.wait_and_pop(data);
where you'll find
data_cond.wait(lk, [this]{return !data_queue.empty();});
which is essentially
while (data_queue.empty()) {
wait(lk);
}
notice the missing '!'.
Now your thread sits there and waits for the queue not to be empty, which will never happen, because the producer id done filling the queue. The thread will never join.
There are many ways to fix this. I'm sure you'll find one on your own.

Synchronizing tasks

I am develeping an application that uses a threadpool, submits tasks to it and synchronizes them. The main thread has to wait until all the submitted tasks from a single loop iteration finish and then it submits another bunch of tasks (because the tasks from the next iteration operate on the same data and they will be dependent on one another).
My question is, what is the best way to do that?
So far, what I have come up with is that each thread, after finishing a task, increments an atomic unsigned integer. When the integer equals the number of submitted tasks, the main thread continues its work and submits another round of tasks.
This is my first multithreaded application.
Is this an optimal and sensible way of dealing with this problem.
I'm using a threadpool class copied from an excellent book "C++ Concurrency in Action: by Anthony Williams.
Here are the classes:
class thread_pool
{
std::atomic_bool done;
thread_safe_queue<std::function<void()> > work_queue;
std::vector<std::thread> threads;
join_threads joiner;
void worker_thread()
{
while(!done)
{
std::function<void()> task;
if(work_queue.try_pop(task))
{
task();
}
else
{
std::this_thread::yield();
}
}
}
public:
thread_pool():
done(false),joiner(threads)
{
unsigned const thread_count=std::thread::hardware_concurrency();
try
{
for(unsigned i=0;i<thread_count;++i)
{
threads.push_back(
std::thread(&thread_pool::worker_thread,this));
}
}
catch(...)
{
done=true;
throw;
}
}
~thread_pool()
{
done=true;
}
template<typename FunctionType>
void submit(FunctionType f)
{
work_queue.push(std::function<void()>(f));
}
};
template<typename T>
class threadsafe_queue
{
private:
mutable std::mutex mut;
std::queue<T> data_queue;
std::condition_variable data_cond;
public:
threadsafe_queue()
{}
void push(T new_value)
{
std::lock_guard<std::mutex> lk(mut);
data_queue.push(std::move(new_value));
data_cond.notify_one();
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty(); });
value = std::move(data_queue.front());
data_queue.pop();
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty(); });
std::shared_ptr<T> res(
std::make_shared<T>(std::move(data_queue.front())));
data_queue.pop();
return res;
}
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty())
return false;
value = std::move(data_queue.front());
data_queue.pop();
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty())
return std::shared_ptr<T>();
std::shared_ptr<T> res(
std::make_shared<T>(std::move(data_queue.front())));
data_queue.pop();
return res;
}
bool empty() const
{
std::lock_guard<std::mutex> lk(mut);
return data_queue.empty();
}
};
The main() function:
std::condition_variable waitForThreads;
std::mutex mut;
std::atomic<unsigned> doneCount = 0;
unsigned threadCount = 4; // sample concurrent thread count that I use for testing
void synchronizeWork()
{
doneCount++;
if (doneCount.load() == threadCount)
{
doneCount = 0;
std::lock_guard<std::mutex> lock(mut);
waitForThreads.notify_one();
}
}
void Task_A()
{
std::cout << "Task A, thread id: " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
synchronizeWork();
}
int main()
{
unsigned const thread_count = std::thread::hardware_concurrency();
thread_pool threadPool;
for (int i = 0; i < 1000; ++i)
{
for (unsigned j = 0; j < thread_count; j++)
threadPool.submit(Task_A);
// Below is my way of synchronizing the tasks
{
std::unique_lock<std::mutex> lock(mut);
waitForThreads.wait(lock);
}
}
I am not familiar with the threadpool class you are using.
Without using such a class, the usual way to do this looks like this:
std::cout << "Spawning 3 threads...\n";
std::thread t1 (pause_thread,1);
std::thread t2 (pause_thread,2);
std::thread t3 (pause_thread,3);
std::cout << "Done spawning threads. Now waiting for them to join:\n";
t1.join();
t2.join();
t3.join();
std::cout << "All threads joined!\n";
I would imagine that any decent threadpool class would allow you to the same sort of thing, even more simply, by giving you a metho to block until all the threads have completed. I suggest you double check the documentation.

Resources