Recently I'm investigate the pthread multi-thread lib and doing some example.
I try to write a Producer-Customer Module: There's a queue to store the Producer's product, and can be get by the Customer.
I set the queue MAX-SIZE as 20. When the queue is full, the Producer thread will wait, until the Customer thread consume one and nofity the Producer thread that he can start produce. And the same as Customer when the queue is empty, the Customer will wait until the Producer thread produce new one and notify him. :-)
I set the Customer thread consume faster than produce, it works fine as the log output in really what I expected. But, when I set the Producer thread consume faster than consume, it seems at last cause a deadlock :-(
I don't kown the reason, can anyone kindly read my code and give me some tips or how to modify the code?
Thanks!
#include "commons.h"
typedef struct tagNode {
struct tagNode *pNext;
char *pContent;
}NodeSt, *PNodeSt;
typedef struct {
size_t mNodeNum;
size_t mNodeIdx;
PNodeSt mRootNode;
}WorkQueue;
#define WORK_QUEUE_MAX 20
static pthread_cond_t g_adder_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t g_adder_mutex = PTHREAD_MUTEX_INITIALIZER;
static WorkQueue g_work_queue = {0};
//------------------------------------------------------------------------
void *customer_thread_runFunc(void *usrdat){
for( ; ; ) {
pthread_mutex_lock(&g_adder_mutex);{
while( g_work_queue.mNodeNum == 0 ) {
pthread_cond_wait(&g_adder_cond, &g_adder_mutex);
}
/********************** CONSUME NEW PRODUCT ***********************/
g_work_queue.mNodeNum --;
if( g_work_queue.mRootNode->pNext != NULL ) {
PNodeSt pTempNode = g_work_queue.mRootNode->pNext;
free( g_work_queue.mRootNode->pContent );
free( g_work_queue.mRootNode );
g_work_queue.mRootNode = pTempNode;
} else {
free( g_work_queue.mRootNode->pContent );
free( g_work_queue.mRootNode );
g_work_queue.mRootNode = NULL;
}
/********************** CONSUME PRODUCT END ***********************/
// Nofity Producer Thread
pthread_cond_signal(&g_adder_cond);
}pthread_mutex_unlock(&g_adder_mutex);
// PAUSE FOR 300ms
usleep(300);
}
return NULL;
}
//------------------------------------------------------------------------
void *productor_thread_runFunc( void *usrdat ) {
for( ; ; ) {
pthread_mutex_lock(&g_adder_mutex); {
char tempStr[64];
PNodeSt pNodeSt = g_work_queue.mRootNode;
while( g_work_queue.mNodeNum >= WORK_QUEUE_MAX ) {
pthread_cond_wait(&g_adder_cond, &g_adder_mutex);
}
/********************** PRODUCE NEW PRODUCT ***********************/
g_work_queue.mNodeNum ++;
g_work_queue.mNodeIdx ++;
if( pNodeSt != NULL ) {
for( ; pNodeSt->pNext != NULL; pNodeSt = pNodeSt->pNext );
pNodeSt->pNext = malloc(sizeof(NodeSt));
memset(pNodeSt->pNext, 0, sizeof(NodeSt));
sprintf( tempStr, "production id: %d", g_work_queue.mNodeIdx);
pNodeSt->pNext->pContent = strdup(tempStr);
} else {
g_work_queue.mRootNode = malloc(sizeof(NodeSt));
memset(g_work_queue.mRootNode, 0, sizeof(NodeSt));
sprintf( tempStr, "production id: %d", g_work_queue.mNodeIdx);
g_work_queue.mRootNode->pContent = strdup(tempStr);
}
/********************** PRODUCE PRODUCT END ***********************/
// Nofity Customer Thread
pthread_cond_signal(&g_adder_cond);
}pthread_mutex_unlock(&g_adder_mutex);
// PAUSE FOR 150ms, faster than Customer Thread
usleep(150);
}
return NULL;
}
//------------------------------------------------------------------------
int main(void) {
pthread_t pt1, pt3;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&pt1, &attr, customer_thread_runFunc, NULL);
pthread_create(&pt3, &attr, productor_thread_runFunc, NULL);
pthread_join(pt1, NULL);
pthread_join(pt3, NULL);
printf("MAIN - main thread finish!\n");
return EXIT_SUCCESS;
}
your producer is waiting on the same condition as your consumer? This is definitely a source of trouble. Think about your code conceptually. What preconditions do the producer need before "producing"? As you mentioned, the buffer need to have space.
I did not look in detail, but you probably need an additional condition variable which is used by the producer (not the same as the consumer). The producer wait only if the queue is full. The consumer signal every times it successfully retrieve something from the queue.
EDIT: Reading the doc of pthread lib, One mutex can be used by two conditions
IDEA OF PSEUDOCODE :)
Mutex mqueue
Condition cprod, ccons
produce()
mqueue.lock
while the queue is full
cprod.wait(mqueue)
end
do the production on queue
mcons.signal
mqueue.unlock
end produce
consume()
mqueue.lock
while the queue is empty
ccons.wait(mqueue)
end
do the consumption on the queue
cprod.signal
mqueue.unlock
end consume
Preferably signal when you have the lock. Here I don't think the order make a difference.
Related
I am trying to implement a simple producer/consumer code using pthreads. The only common shared data between producer and consumer thread is the count variable used for counting the number of available elements in the shared array. What is happening is the count updated in one thread is not getting reflected in other. How can I make sure the writes to count in one thread appear in other as well? Am I missing something?
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define ARRAY_SIZE 100
int array[ARRAY_SIZE];
volatile int count;
int head;
int tail;
pthread_cond_t full = PTHREAD_COND_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *producer(void *args)
{
int res = 0;
while (1) {
pthread_mutex_lock(&mutex);
if (count == ARRAY_SIZE) {
printf("\nNo space for new items waiting for consumer to consume");
pthread_cond_wait(&empty, &mutex);
// Sometimes, why is count variable still ARRAY_SIZE.
// How do I make sure writes to 'count' variable in
// consumer thread is visible immediately in producer
// thread?
if (count == ARRAY_SIZE) {
printf("\ncount is still ARRAY_SIZE");
exit(0);
}
}
head %= ARRAY_SIZE;
count++;
array[head] = head;
printf("\nproduced %d/%d", head, count);
head++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&full);
}
}
void *consumer(void *args)
{
int res = 0;
while (1) {
pthread_mutex_lock(&mutex);
if (count == 0) {
printf("\nNo items available waiting for producer to produce");
pthread_cond_wait(&full, &mutex);
// Sometimes, why is count variable still zero. How do I
// make sure writes to 'count' variable in producer
// thread is visible immediately in consumer thread?
if (count == 0) {
printf("\ncount is still zero");
exit(0);
}
}
tail %= ARRAY_SIZE;
int ele = array[tail];
count--;
printf("\nconsumed %d/%d", tail, count);
tail++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&empty);
}
}
int main()
{
pthread_t producer_thread;
pthread_t consumer_thread;
int ret = 0;
setbuf(stdout, NULL);
ret = pthread_create(&producer_thread, NULL, producer, NULL);
if (ret != 0) {
printf("\nUnable to create producer thread %d", ret);
goto exit;
}
ret = pthread_create(&consumer_thread, NULL, consumer, NULL);
if (ret != 0) {
printf("\nUnable to create consumer thread %d", ret);
goto exit;
}
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
exit:
return ret;
}
produced 72/99
produced 73/100
No space for new items waiting for consumer to consume
consumed 74/99
consumed 75/98
consumed 76/97
consumed 77/96
produced 74/97
produced 75/98
produced 76/99
produced 77/100
No space for new items waiting for consumer to consume
count is still ARRAY_SIZE <------ incorrect
consumed 21/2
consumed 22/1
consumed 23/0
No items available waiting for producer to produce
produced 24/1
consumed 24/0
No items available waiting for producer to produce
produced 25/1
produced 26/2
produced 27/3
consumed 25/2
consumed 26/1
consumed 27/0
No items available waiting for producer to produce
count is still zero <------ incorrect
Solution that worked after the fix from Zan Lynx
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define ARRAY_SIZE 100
int array[ARRAY_SIZE];
volatile int count;
int head;
int tail;
pthread_cond_t full = PTHREAD_COND_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *producer(void *args)
{
int res = 0;
while (1) {
pthread_mutex_lock(&mutex);
if (count == ARRAY_SIZE) {
printf("\nNo space for new items waiting for consumer to consume");
// Spurious wakeups from the pthread_cond_timedwait() or
// pthread_cond_wait() functions may occur. Since the
// return from pthread_cond_timedwait() or
// pthread_cond_wait() does not imply anything about the
// value of this predicate, the predicate should be
// re-evaluated upon such return.
while (count == ARRAY_SIZE)
pthread_cond_wait(&empty, &mutex);
}
head %= ARRAY_SIZE;
count++;
array[head] = head;
printf("\nproduced %d/%d", head, count);
head++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&full);
}
return NULL;
}
void *consumer(void *args)
{
int res = 0;
while (1) {
pthread_mutex_lock(&mutex);
if (count == 0) {
printf("\nNo items available waiting for producer to produce");
// Spurious wakeups from the pthread_cond_timedwait() or
// pthread_cond_wait() functions may occur. Since the
// return from pthread_cond_timedwait() or
// pthread_cond_wait() does not imply anything about the
// value of this predicate, the predicate should be
// re-evaluated upon such return.
while (count == 0)
pthread_cond_wait(&full, &mutex);
}
tail %= ARRAY_SIZE;
int ele = array[tail];
count--;
printf("\nconsumed %d/%d", tail, count);
tail++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&empty);
}
return NULL;
}
int main()
{
pthread_t producer_thread;
pthread_t consumer_thread;
int ret = 0;
setbuf(stdout, NULL);
ret = pthread_create(&producer_thread, NULL, producer, NULL);
if (ret != 0) {
printf("\nUnable to create producer thread %d", ret);
goto exit;
}
ret = pthread_create(&consumer_thread, NULL, consumer, NULL);
if (ret != 0) {
printf("\nUnable to create consumer thread %d", ret);
goto exit;
}
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
exit:
return ret;
}
I believe you missed the fact that condition waits must always check the predicate again after the wait returns. There must be a loop.
The wait may end for all sorts of reasons besides a signal/notify call.
I'm trying to implement an multi-thread job, a producer and a consumer, and basically what I want to do is, when consumer finishes the data, it notifies the producer so that producer provides new data.
The tricky part is, in my current impl, producer and consumer both notifies each other and waits for each other, I don't know how to implement this part correctly.
For example, see the code below,
mutex m;
condition_variable cv;
vector<int> Q; // this is the queue the consumer will consume
vector<int> Q_buf; // this is a buffer Q into which producer will fill new data directly
// consumer
void consume() {
while (1) {
if (Q.size() == 0) { // when consumer finishes data
unique_lock<mutex> lk(m);
// how to notify producer to fill up the Q?
...
cv.wait(lk);
}
// for-loop to process the elems in Q
...
}
}
// producer
void produce() {
while (1) {
// for-loop to fill up Q_buf
...
// once Q_buf is fully filled, wait until consumer asks to give it a full Q
unique_lock<mutex> lk(m);
cv.wait(lk);
Q.swap(Q_buf); // replace the empty Q with the full Q_buf
cv.notify_one();
}
}
I'm not sure this the above code using mutex and condition_variable is the right way to implement my idea,
please give me some advice!
The code incorrectly assumes that vector<int>::size() and vector<int>::swap() are atomic. They are not.
Also, spurious wakeups must be handled by a while loop (or another cv::wait overload).
Fixes:
mutex m;
condition_variable cv;
vector<int> Q;
// consumer
void consume() {
while(1) {
// Get the new elements.
vector<int> new_elements;
{
unique_lock<mutex> lk(m);
while(Q.empty())
cv.wait(lk);
new_elements.swap(Q);
}
// for-loop to process the elems in new_elements
}
}
// producer
void produce() {
while(1) {
vector<int> new_elements;
// for-loop to fill up new_elements
// publish new_elements
{
unique_lock<mutex> lk(m);
Q.insert(Q.end(), new_elements.begin(), new_elements.end());
cv.notify_one();
}
}
}
Maybe that is close to what you want to achive. I used 2 conditional variables to notify producers and consumers between each other and introduced variable denoting which turn is now:
#include <ctime>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
template<typename T>
class ReaderWriter {
private:
std::vector<std::thread> readers;
std::vector<std::thread> writers;
std::condition_variable readerCv, writerCv;
std::queue<T> data;
std::mutex readerMutex, writerMutex;
size_t noReaders, noWriters;
enum class Turn { WRITER_TURN, READER_TURN };
Turn turn;
void reader() {
while (1) {
{
std::unique_lock<std::mutex> lk(readerMutex);
while (turn != Turn::READER_TURN) {
readerCv.wait(lk);
}
std::cout << "Thread : " << std::this_thread::get_id() << " consumed " << data.front() << std::endl;
data.pop();
if (data.empty()) {
turn = Turn::WRITER_TURN;
writerCv.notify_one();
}
}
}
}
void writer() {
while (1) {
{
std::unique_lock<std::mutex> lk(writerMutex);
while (turn != Turn::WRITER_TURN) {
writerCv.wait(lk);
}
srand(time(NULL));
int random_number = std::rand();
data.push(random_number);
std::cout << "Thread : " << std::this_thread::get_id() << " produced " << random_number << std::endl;
turn = Turn::READER_TURN;
}
readerCv.notify_one();
}
}
public:
ReaderWriter(size_t noReadersArg, size_t noWritersArg) : noReaders(noReadersArg), noWriters(noWritersArg), turn(ReaderWriter::Turn::WRITER_TURN) {
}
void run() {
int noReadersArg = noReaders, noWritersArg = noWriters;
while (noReadersArg--) {
readers.emplace_back(&ReaderWriter::reader, this);
}
while (noWritersArg--) {
writers.emplace_back(&ReaderWriter::writer, this);
}
}
~ReaderWriter() {
for (auto& r : readers) {
r.join();
}
for (auto& w : writers) {
w.join();
}
}
};
int main() {
ReaderWriter<int> rw(5, 5);
rw.run();
}
Here's a code snippet. Since the worker treads are already synchronized, requirement of two buffers is ruled out. So a simple queue is used to simulate the scenario:
#include "conio.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <atomic>
#include <condition_variable>
using namespace std;
enum state_t{ READ = 0, WRITE = 1 };
mutex mu;
condition_variable cv;
atomic<bool> running;
queue<int> buffer;
atomic<state_t> state;
void generate_test_data()
{
const int times = 5;
static int data = 0;
for (int i = 0; i < times; i++) {
data = (data++) % 100;
buffer.push(data);
}
}
void ProducerThread() {
while (running) {
unique_lock<mutex> lock(mu);
cv.wait(lock, []() { return !running || state == WRITE; });
if (!running) return;
generate_test_data(); //producing here
lock.unlock();
//notify consumer to start consuming
state = READ;
cv.notify_one();
}
}
void ConsumerThread() {
while (running) {
unique_lock<mutex> lock(mu);
cv.wait(lock, []() { return !running || state == READ; });
if (!running) return;
while (!buffer.empty()) {
auto data = buffer.front(); //consuming here
buffer.pop();
cout << data << " \n";
}
//notify producer to start producing
if (buffer.empty()) {
state = WRITE;
cv.notify_one();
}
}
}
int main(){
running = true;
thread producer = thread([]() { ProducerThread(); });
thread consumer = thread([]() { ConsumerThread(); });
//simulating gui thread
while (!getch()){
}
running = false;
producer.join();
consumer.join();
}
Not a complete answer, though I think two condition variables could be helpful, one named buffer_empty that the producer thread will wait on, and another named buffer_filled that the consumer thread will wait on. Number of mutexes, how to loop, and so on I cannot comment on, since I'm not sure about the details myself.
Accesses to shared variables should only be done while holding the
mutex that protects it
condition_variable::wait should check a condition.
The condition should be a shared variable protected by the mutex that you pass to condition_variable::wait.
The way to check the condition is to wrap the call to wait in a while loop or use the 2-argument overload of wait (which is
equivalent to the while-loop version)
Note: These rules aren't strictly necessary if you truly understand what the hardware is doing. However, these problems get complicated quickly when with simple data structures, and it will be easier to prove that your algorithm is working correctly if you follow them.
Your Q and Q_buf are shared variables. Due to Rule 1, I would prefer to have them as local variables declared in the function that uses them (consume() and produce(), respectively). There will be 1 shared buffer that will be protected by a mutex. The producer will add to its local buffer. When that buffer is full, it acquires the mutex and pushes the local buffer to the shared buffer. It then waits for the consumer to accept this buffer before producing more data.
The consumer waits for this shared buffer to "arrive", then it acquires the mutex and replaces its empty local buffer with the shared buffer. Then it signals to the producer that the buffer has been accepted so it knows to start producing again.
Semantically, I don't see a reason to use swap over move, since in every case one of the containers is empty anyway. Maybe you want to use swap because you know something about the underlying memory. You can use whichever you want and it will be fast and work the same (at least algorithmically).
This problem can be done with 1 condition variable, but it may be a little easier to think about if you use 2.
Here's what I came up with. Tested on Visual Studio 2017 (15.6.7) and GCC 5.4.0. I don't need to be credited or anything (it's such a simple piece), but legally I have to say that I offer no warranties whatsoever.
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::vector<int> g_deliveryBuffer;
bool g_quit = false;
std::mutex g_mutex; // protects g_deliveryBuffer and g_quit
std::condition_variable g_producerDeliver;
std::condition_variable g_consumerAccepted;
// consumer
void consume()
{
// local buffer
std::vector<int> consumerBuffer;
while (true)
{
if (consumerBuffer.empty())
{
std::unique_lock<std::mutex> lock(g_mutex);
while (g_deliveryBuffer.empty() && !g_quit) // if we beat the producer, wait for them to push to the deliverybuffer
g_producerDeliver.wait(lock);
if (g_quit)
break;
consumerBuffer = std::move(g_deliveryBuffer); // get the buffer
}
g_consumerAccepted.notify_one(); // notify the producer that the buffer has been accepted
// for-loop to process the elems in Q
// ...
consumerBuffer.clear();
// ...
}
}
// producer
void produce()
{
std::vector<int> producerBuffer;
while (true)
{
// for-loop to fill up Q_buf
// ...
producerBuffer = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// ...
// once Q_buf is fully filled, wait until consumer asks to give it a full Q
{ // scope is for lock
std::unique_lock<std::mutex> lock(g_mutex);
g_deliveryBuffer = std::move(producerBuffer); // ok to push to deliverybuffer. it is guaranteed to be empty
g_producerDeliver.notify_one();
while (!g_deliveryBuffer.empty() && !g_quit)
g_consumerAccepted.wait(lock); // wait for consumer to signal for more data
if (g_quit)
break;
// We will never reach this point if the buffer is not empty.
}
}
}
int main()
{
// spawn threads
std::thread consumerThread(consume);
std::thread producerThread(produce);
// for for 5 seconds
std::this_thread::sleep_for(std::chrono::seconds(5));
// signal that it's time to quit
{
std::lock_guard<std::mutex> lock(g_mutex);
g_quit = true;
}
// one of the threads may be sleeping
g_consumerAccepted.notify_one();
g_producerDeliver.notify_one();
consumerThread.join();
producerThread.join();
return 0;
}
I have a data structure :
struct {
mutex m;
condition_variable cv_p2c;
queue<int> qi;
bool finished;
} sdf_inst;
and I have a producer that generate 100 integer and insert them into queue qi after getting lock.
void producer () {
for(int i = 0 ; i < 100 ; i++ ) {
{
unique_lock<mutex> ulck(sdf_inst.m);//LOCK
sdf_inst.qi.push(i);
cout<<"adding "<<i<<endl<<flush;
}
sdf_inst.cv_p2c.notify_one();
}
unique_lock<mutex> ulck(sdf_inst.m);//LOCK
sdf_inst.finished=true;
sdf_inst.cv_p2c.notify_one();
}
After all datas have been inserted, it will acquire the lock and set the finished flag, and exit.
And I have another consumer :
void consumer () {
while(true) {
unique_lock<mutex> ulck(sdf_inst.m);//LOCK
sdf_inst.cv_p2c.wait(ulck,[]{return sdf_inst.qi.empty()==false || sdf_inst.finished==true ; });
print_all();
if(sdf_inst.finished=true) return;
}
}
It just acquire lock, and wait for notify from producer, and print all the data currently in the queue qi with the print_all function below:
void print_all () {
while(sdf_inst.qi.empty()==false) {
int i = sdf_inst.qi.front();
sdf_inst.qi.pop();
cout<<"shared_i "<< i <<endl<<flush;
}
return;
}
I think it should print all the 100 data, but sometimes it print only part of them.
I have studied the code carefully and find no error in synchronization, so may the lost data caused by the queue leakage?
I found the cause of this problem, in consumer():
if(sdf_inst.finished=true) return;
should be
if ( sdf_inst.finished )
{
return;
}
I had implemented the Bounded buffer(Buffer size 5) problem using three semaphores, two counting (with count MAX 5) and one binary semaphore for critical section.
The producer and consumer processes were separate and were sharing the buffer.
Then I have moved on to try the same problem, this time with One Parent process that sets up the shared memory( Buffer) and two child processes which act like Producer and consumer.
I almost copied whatever Implemented in the earlier code into the new one (Producer goes into the ret ==0 and i==0 block and Consumer goes into ret ==0 and i==1 block..Here i is the count of the child processes);
However my process blocks. The pseudo implementation of the code is as follows:
Please suggest if the steps are correct. I think i may be going wrong with the sharing of semaphores and their values. The shared memory anyways gets shared implicitly between the parent and both child processes.
struct shma{readindex,writeindex,buf_max,char buf[5],used_count};
main()
{
struct shma* shm;
shmid = shmget();
shm = shmat(shmid);
init_shma(0,0,5,0);
while(i++<2)
{
ret = fork();
if(ret > 0 )
continue;
if(ret ==0 )
{
if(i==0)
{
char value;
sembuf[3]; semun u1; values[] = {5,1,0}; // Sem Numbers 1,2,3
semid = semget(3 semaphores);
semctl(SETALL,values);
while(1)
{
getValuefromuser(&value);
decrement(1);
decrement(2); // Critical section
*copy value to shared memory*
increment(2);
increment(3); // used count
}
}
if(i==1)
{
char value;
sembuf[3]; semun u1; values[] = {5,1,0}; // Sem Numbers 1,2,3
semid = semget(3 semaphores);
semctl(SETALL,values);
while(1)
{
decrement(3); // Used Count
decrement(2); // Critical Section
read and print(&value); // From Shared Memory
increment(2);
increment(1); // free slots
}
}
}
}//while
Cleanup Code.
}//main
Should I get semaphore ids in both child processes..or is there something else missing.
The pseudo code implementation would be something like this. Get the semaphore ID in the child process using same key, either using ftok or hardcoded key, then obtain the current value of semaphore then perform appropriate operations.
struct shma{readindex,writeindex,buf_max,char buf[5],used_count};
main()
{
struct shma* shm;
shmid = shmget();
shm = shmat(shmid);
init_shma(0,0,5,0);
sembuf[3]; semun u1; values[] = {5,1,0}; // Sem Numbers 1,2,3
semid = semget(3 semaphores);
semctl(SETALL,values);
while(i++<2)
{
ret = fork();
if(ret > 0 )
continue;
if(ret ==0 )
{
if(i==0)
{
char value;
sembuf[3]; semun u1; values[];
semid = semget(3 semaphores);
while(1)
{
getValuefromuser(&value);
decrement(1);
decrement(2); // Critical section
*copy value to shared memory*
increment(2);
increment(3); // used count
}
}
if(i==1)
{
char value;
sembuf[3]; semun u1; values[];
while(1)
{
getValuefromuser(&value);
decrement(3); // Used Count
decrement(2); // Critical Section
read and print(&value); // From Shared Memory
increment(2);
increment(1); // free slots
}
}
}
}//while
Cleanup Code.
}//main
I ultimately found a problem with my understanding.
I have to create and set up a semaphore or three semaphores in the parent process and then obtain their value in the respective producer and consumer child processes then use them accordingly.
I was earlier, creating semaphores in both producer and consumer.
silly me.!!
I need to implement producer-consumer problem in my project. N consumers and M producers will be created. A producer will use publish(v) call to reach v data to consumer. A consumer will use get_data(v) call to get a copy of data v. I really don't know how to implement it. Please help me.
I am going to use C to implement it. I will create n process for consumers and m process for producers. If a producer publish a data, other producers can not do it until all consumers get it. I will use semaphores and shared memory to exchange data.
I found something which does similar job. But it is using threads but i need process instead. How can i change this.
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#define BUFF_SIZE 4
#define FULL 0
#define EMPTY 0
char buffer[BUFF_SIZE];
int nextIn = 0;
int nextOut = 0;
sem_t empty_sem_mutex; //producer semaphore
sem_t full_sem_mutex; //consumer semaphore
void Put(char item)
{
int value;
sem_wait(&empty_sem_mutex); //get the mutex to fill the buffer
buffer[nextIn] = item;
nextIn = (nextIn + 1) % BUFF_SIZE;
printf("Producing %c ...nextIn %d..Ascii=%d\n",item,nextIn,item);
if(nextIn==FULL)
{
sem_post(&full_sem_mutex);
sleep(1);
}
sem_post(&empty_sem_mutex);
}
void * Producer()
{
int i;
for(i = 0; i < 10; i++)
{
Put((char)('A'+ i % 26));
}
}
void Get()
{
int item;
sem_wait(&full_sem_mutex); // gain the mutex to consume from buffer
item = buffer[nextOut];
nextOut = (nextOut + 1) % BUFF_SIZE;
printf("\t...Consuming %c ...nextOut %d..Ascii=%d\n",item,nextOut,item);
if(nextOut==EMPTY) //its empty
{
sleep(1);
}
sem_post(&full_sem_mutex);
}
void * Consumer()
{
int i;
for(i = 0; i < 10; i++)
{
Get();
}
}
int main()
{
pthread_t ptid,ctid;
//initialize the semaphores
sem_init(&empty_sem_mutex,0,1);
sem_init(&full_sem_mutex,0,0);
//creating producer and consumer threads
if(pthread_create(&ptid, NULL,Producer, NULL))
{
printf("\n ERROR creating thread 1");
exit(1);
}
if(pthread_create(&ctid, NULL,Consumer, NULL))
{
printf("\n ERROR creating thread 2");
exit(1);
}
if(pthread_join(ptid, NULL)) /* wait for the producer to finish */
{
printf("\n ERROR joining thread");
exit(1);
}
if(pthread_join(ctid, NULL)) /* wait for consumer to finish */
{
printf("\n ERROR joining thread");
exit(1);
}
sem_destroy(&empty_sem_mutex);
sem_destroy(&full_sem_mutex);
//exit the main thread
pthread_exit(NULL);
return 1;
}
I'd suggest you to make a plan and start reading. For example:
Read about how to create and manage threads. Hint: pthread.
Think how will the threads communicate - usually they use common data structure. Hint: message queue
Think how to protect the data structure, so both threads can read and write safely. Hint: mutexes.
Implement consumer and producer code.
Really, if you want more information you have to work a bit and ask more specific questions. Good luck!