Mycale Radcliffe
Mycale Radcliffe

Reputation: 1

Producer-Consumer Problem in c++ using pthread

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

Answers (1)

Igor Tandetnik
Igor Tandetnik

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

Related Questions