Lets say I have a buffer that has 3 producer threads and 5 consumer threads inserting and consuming to/from the buffer.
I only want to allow 1 producer or up to 3 consumer threads access the buffer at any given time.
Up to 3 consumers can peek at the top element in the buffer, only, if no producer is accessing it. If more than 1 consumer thread does access the buffer, the last thread to leave must delete the top element.
Now this is part of a class assignment, and the assignment explicitly states to use semaphores. However, I can't think of a way to really implement this wording exactly using only semaphores.
The pseudo code -I think- should look like this: (I'm not worrying about an empty or full buffer, just this sub-part of the problem)
sem_init(&binary, 0, 1); //Init binary semaphore to 1
sem_init(&consumerCount, 0 , 3); //Allows 3 consumers to access
producer()
{
createItem()
sem_wait(&binary)
appendItem()
sem_post(&binary)
}
//The above assures nothing else can access buffer while appending an item
consumer()
{
while( binary unlocked)
{
sem_wait(&binary) and sem_wait(&consumerCount) //Locks the producers out
//Allows 3 consumers in
peek() //Gets copy of top item
if( last consumer out )
{
delete() //Deletes top item
sem_post(&binary) //Allow producer access back since last one out
}
sem_post(&consumerCount)
}
}
I think that's the gist of the logic, problem is how to implement this with just semaphores. How do I allow only 1 producer in with a semaphore but allow 3 consumers in on the other side? It seems like I would need to use something besides a semaphore.
Also, please correct any of the logic if needed, this is meant to just be a general idea.
You can solve the problem with two semaphores. The first semaphore is used for exclusive access by producers. The second semaphore is used for the shared access. The producer tries to acquire all three permits in order to lock out the consumers.
sem_init(&exclusive, 0, 1);
sem_init(&shared, 0, 3);
void producer()
{
sem_wait(&exclusive);
sem_wait(&shared);
sem_wait(&shared);
sem_wait(&shared);
// critical section
sem_post(&shared);
sem_post(&shared);
sem_post(&shared);
sem_post(&exclusive);
}
void consumer()
{
sem_wait(&shared);
// critical section
sem_post(&shared);
}
Related
This is the solution using 3 semaphores. Wondering if there's a way to do with fewer and if not, why not?
sem_t full; // # of filled slots
sem_t empty; // # of empty slots
sem_t mutex; // mutual exclusion
sem_init(&full, 0, 0);
sem_init(&empty, 0, N);
sem_init(&mutex, 0, 1);
Producer(){
sem_down(empty);
sem_down(&mutex);
// fill a slot
sem_up(&mutex);
sem_up(full);
}
Consumer() {
sem_down(full);
sem_down(&mutex);
// empty a slot
sem_up(&mutex);
sem_up(empty);
}
The only way to avoid the the mutex is if all operations inside the semaphore are atomic (can be rare). The mutex is there to make sure the dangerous bits happen one at a time and without being interrupted.
Imagine if you had two threads attempting to do something that depended on each other.
Thread 1: Add 3 to the ordered list
Thread 2: Add 4 to the ordered list
List: { 1, 2, 5, 7}
Thread 2 needs to see where thread 1 sticks his number before inserting his own. Therefore we use a mutex to make sure only one thread at a time tries to insert their number into the list.
The way it is written in your example (and others online) might make one believe the whole process needs to be inside the mutex. If you did this only one thread would be able to work at a time! In actuality you would do stuff that doesn't depend on other threads outside of the mutex but inside the semaphore (say generating a random number) and only guard the insertion of the number into the list.
semaphore(x)
long_expensive_computation
mutex(y)
order_critical_stuff
release(y)
release(x)
I'm trying to make a producer/ consumer application. The problem is, my producer is fillin the whole buffer THEN the consumer is removing the whole buffer... wasn't the consumer supposed to remove an item from the buffer as soon as the producer make a post to the semaphore ?
my code:
void* producerFunc(void* arg)
{
while(n_insertions < N_PRODUCTS)
{
sem_wait(&sem_postAvaliable);
sem_wait(&mutex);
//Insert Item
sem_post(&mutex);
sem_post(&sem_posTaken);
}
pthread_exit(NULL);
}
void* consumerFunc(void* arg)
{
while(n_consumed < N_PRODUCTS)
{
sem_wait(&sem_posTaken);
sem_wait(&mutex);
//Remove from bufer
sem_post(&mutex);
sem_post(&sem_postAvaliable);
}
pthread_exit(NULL);
}
n_insertionsis a global integer that counts the number of items inserted into the buffer;
n_consumed is a global integer that counts the number of times the consumer consumed an item from the buffer.
At a very high level, when you do a sem_post(&sem_posTaken) you are telling the consumers "Hey!, you can consume something", but after that depending on the processor scheduler the producers may continue producing until the counter of the semaphore doesn't allow them, so maybe a consumer consume right after the producer insert something or maybe after 3 inserts, who knows? The thread is blocked when you try to make a sem_wait of a semaphore whose counter is 0.
If you want to alternate between an insert and a remove, try initializing sem_postAvaliable to 1, that way you would allowing only one insertion at first, because the other threads would be blocked waiting a sem_post(&sem_postAvaliable), then only one consumer could consume whatever you inserted in the buffer and so on, but note that in this case a buffer with size larger than 1 would be meaningless.
I'm tring to solve producer consumer problem by using monitoring thread.
Basically, when we try to solve this problem, we can easly solve it by using semaphore and mutex(semaphore detect empty or full state keep stable critical section, and mutex keep shared part where producer producing, consumer consuming)
In this problem I want to using monitoring thread to check how many item is in shared memory and this thread must enter critical section after producer or consumer doing their work. It kind of acknowledgement thing
For example
Produce
Ack, buffer have 1 item
Consume
Ack, buffer have 0 item
Produce
Ack, buffer have 1 item
Produce
Ack, buffer have 2 item
I was thinking use two more sem_t,
sem_t m1;
sem_t m2;
Void *produce()
{
sem_wait(&m1);
sem_wait(&m2);
....
sem_signal(&m1);
}
Void *consumer()
{
sem_wait(&m1);
sem_wait(&m2);
....
sem_signal(&m2);
}
Void *monitor()
{
if(m1==o && m2==1)
sem_wait();
else if(m1==1 && m2==0)
sem_wait(m1);
....
sem_signal(m1);
sem_signal(m2);
}
producer and consumer only can enter critical section when both m1 and m2 is bigger then 0, and when they done their tasks they call sem_signal just one time for m1 or m2. this block producer and consumer, only monitoring thread can enter critical section. after monitoring thread finishing own task, it calls sem_signal for m1, m2, then producer or consumer can enter the critical section (each of sem object is kind of mutex, binary semaphore)
but it doesn't work..
I can't find what is my problem.
Is Sem object can't use if statement?
or, my idea is have something problem?
thanks for reading my long text
Following Code solves ( I think) producer-consumer problem with two threads using only one semaphore.
sem_t sem; //init to 1
int arr[100];
void producer()
{
while(;;) {
sem_wait(sem)
if it is fully filled {
sem_post(sem);
} else {
run 100 times and fill the items
sem_post(sem);
}
sleep(2);
}
}
void consumer()
{
while(;;) {
sem_wait(sem)
if it is empty {
sem_post(sem);
} else {
run 100 times and read the items
reset the start index to 0 so producer could fill again
sem_post(sem);
}
sleep(2);
}
}
int main()
{
//create thread 1 calling consumer
//create thread 2 calling producer
}
Question is why two semaphores (empty and full) are used? Cant the problem be solved with one semaphore?
The reason you need two semaphores is that the producer cannot do anything when the "bin" or whatever the producer and consumer are sharing is full, but the consumer cannot do anything when the bin is empty.
Therefore, the producer needs to have a semaphore for full and the consumer one for empty.
Question is why two semaphores (empty and full) are used? Cant the problem be solved with one semaphore?
Generally speaking, it is needed two some sort of condition variables (empty and full) to solve the problem. These variables used in wait() and notify() semantics.
One semaphore can be use as one of such variables in the given problem, so two semaphores are sufficient.
Another way is to use two actual condition variables with single monitor/mutex (see Using monitors section at http://en.wikipedia.org/wiki/Producer–consumer_problem).
Your variant is similar to the last case, but you use busy-wait(sleep 2) instead of actual waiting on condition variable(wait()).
So, I am trying to implement a concurrent queue in C. I have split the methods into "read methods" and "write methods". So, when accessing the write methods, like push() and pop(), I acquire a writer lock. And the same for the read methods. Also, we can have several readers but only one writer.
In order to get this to work in code, I have a mutex lock for the entire queue. And two condition locks - one for the writer and the other for the reader. I also have two integers keeping track of the number of readers and writers currently using the queue.
So my main question is - how to implement several readers accessing the read methods at the same time?
At the moment this is my general read method code: (In psuedo code - not C. I am actually using pthreads).
mutex.lock();
while (nwriter > 0) {
wait(&reader);
mutex.unlock();
}
nreader++;
//Critical code
nreader--;
if (nreader == 0) {
signal(&writer)
}
mutex.unlock
So, imagine we have a reader which holds the mutex. Now any other reader which comes along, and tries to get the mutex, would not be able to. Wouldn't it block? Then how are many readers accessing the read methods at the same time?
Is my reasoning correct? If yes, how to solve the problem?
If this is not for an exercise, use read-write lock from pthreads (pthread_rwlock_* functions).
Also note that protecting individual calls with a lock stil might not provide necessary correctness guarantees. For example, a typical code for popping an element from STL queue is
if( !queue.empty() ) {
data = queue.top();
queue.pop();
}
And this will fail in concurrent code even if locks are used inside the queue methods, because conceptually this code must be an atomic transaction, but the implementation does not provide such guarantees. A thread may pop a different element than it read by top(), or attempt to pop from empty queue, etc.
Please find the following read\write functions.
In my functions, I used canRead and canWrite mutexes and nReads for number of readers:
Write function:
lock(canWrite) // Wait if mutex if not free
// Write
unlock(canWrite)
Read function:
lock(canRead) // This mutex protect the nReaders
nReaders++ // Init value should be 0 (no readers)
if (nReaders == 1) // No other readers
{
lock(canWrite) // No writers can enter critical section
}
unlock(canRead)
// Read
lock(canRead)
nReaders--;
if (nReaders == 0) // No more readers
{
unlock(canWrite) // Writer can enter critical secion
}
unlock(canRead)
A classic solution is multiple-readers, single-writer.
A data structure begins with no readers and no writers.
You permit any number of concurrent readers.
When a writer comes along, you block him till all current readers complete; then you let him go (any new readers and writers which come along which the writer is blocked queue up behind him, in order).
You may try this library it is built in c native, lock free, suitable for cross-platform lfqueue,
For Example:-
int* int_data;
lfqueue_t my_queue;
if (lfqueue_init(&my_queue) == -1)
return -1;
/** Wrap This scope in other threads **/
int_data = (int*) malloc(sizeof(int));
assert(int_data != NULL);
*int_data = i++;
/*Enqueue*/
while (lfqueue_enq(&my_queue, int_data) == -1) {
printf("ENQ Full ?\n");
}
/** Wrap This scope in other threads **/
/*Dequeue*/
while ( (int_data = lfqueue_deq(&my_queue)) == NULL) {
printf("DEQ EMPTY ..\n");
}
// printf("%d\n", *(int*) int_data );
free(int_data);
/** End **/
lfqueue_destroy(&my_queue);