Reputation: 1
I am currently learning multithreading and semaphores and have been assigned to recreate the problem using only pthread. I found a solution that uses std::thread and have been working to convert it to pthreads, but I am having problems with the pthread_create method.
I am not sure specifically how to turn this statement
pthread_create(&threads[i], NULL, &Producer::run, &p);
into something that works with pthreads.
Here is my whole code for reference
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <deque>
#include <condition_variable>
#include <semaphore.h>
#include <queue>
#ifdef _WIN32
#include <windows.h>
void sleeps(unsigned milliseconds)
{
Sleep(milliseconds);
}
#else
#include <unistd.h>
void sleeps(unsigned milliseconds) {
usleep(milliseconds * 1000); // takes microseconds
}
#endif
class Widget {
public:
int data;
void setData(int data) {
this->data = data;
}
};
class Buffer
{
public:
void add(Widget widget) {
while (true) {
pthread_mutex_lock(&lock);
sharedBuffer.push_back(widget);
pthread_mutex_unlock(&lock);
return;
}
}
Widget remove() {
while(true) {
pthread_mutex_lock(&lock);
Widget backElem = sharedBuffer.back();
sharedBuffer.pop_back();
pthread_mutex_unlock(&lock);
return backElem;
}
}
Buffer() {}
private:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
std::deque<Widget> sharedBuffer;
};
class Producer{
Buffer& sharedBuffer;
pthread_mutex_t coutMut;
public:
Producer(Buffer& buffer)
: sharedBuffer(buffer), coutMut(PTHREAD_MUTEX_INITIALIZER)
{}
void run() {
while(true) {
Widget widget;
widget.setData(rand() % 10);
sharedBuffer.add(widget);
pthread_mutex_lock(&coutMut);
std::cout << "Added: " << widget.data << "\n";
sleeps(50);
pthread_mutex_unlock(&coutMut);
}
}
};
class Consumer
{
Buffer& sharedBuffer;
pthread_mutex_t coutMut;
public:
Consumer(Buffer& buffer)
: sharedBuffer(buffer), coutMut(PTHREAD_MUTEX_INITIALIZER)
{}
void run() {
while(true) {
Widget widget;
widget = sharedBuffer.remove();
pthread_mutex_lock(&coutMut);
std::cout << "Removed: " << widget.data << "\n";
sleeps(50);
pthread_mutex_unlock(&coutMut);
}
}
};
int main(int argc, char *argv[]) {
typedef std::string string_std;
const int producerT = std::stoi(argv[1]);
const int consumerT = std::stoi(argv[2]);
int threadSize = producerT + consumerT;
pthread_t threads[threadSize];
void *status;
Buffer b1;
Producer p(b1);
Consumer c(b1);
for (int i = 0; i < producerT; i++) {
pthread_create(&threads[i], NULL, &Producer::run, &p);
}
for (int i = producerT; i < threadSize; i++) {
pthread_create(&threads[i], NULL, &Consumer::run, &c);
}
sleeps(5000);
for (int i = 0; i < threadSize; i++) {
pthread_join(threads[i], &status);
}
exit(0);
}
Upvotes: 0
Views: 349
Reputation: 52471
You are probably looking for something like this:
class Producer {
static void static_run(void* pThis) {
static_cast<Producer*>(pThis)->run();
}
void run() {
// Real work done here.
}
};
// At call site
Producer p;
pthread_create(&threads[i], NULL, Producer::static_run, &p);
The point is that pthread_create
wants a C-style function - either a standalone non-member function, or a static member function. So you need an adapter (sometimes referred to as a "trampoline") that satisfies the requirements, and then turns around and calls the member function.
Upvotes: 1