C solution for producer-consumer with only ONE semaphore - c

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()).

Related

Use of semaphores in read/write threads

I have a problem where I have multiple threads(Read threads) where shared data is to be read, no issue so far.
This shared data is to be updated in another single thread(Write thread).
During this write no reads should be done to prevent corrupt data.
My initial thought was to use a semaphore(Posix semaphore, ) after doing some reading.
Using sem_wait() and sem_post() works fine for blocking, decrementing and incrementing the semaphore inside the read threads. As long as the semaphore is not 0, sem_wait() does not block and allow the thread to read the data.
My issue starts here.
Now I would like to have the condition for the write thread to be opposite of what sem_wait() actually does. I would like the write thread to be blocked as long as the semaphore is larger than zero as this means there is a read thread in progress.
Is there any way for it to block while semaphore is larger than 0 or is there any different approach that could solve this issue?
Thank you!
One option is to use POSIX read-write lock, where multiple readers can acquire the lock unless there is a writer.
Another option is a lower-level seqlock but it may be trickier to implement and use correctly because it requires a good grasp of the memory model data races and memory order.
If you must use semaphores, and are in a unix-y kind of environment, I think you are stuck with something like this:
typedef struct rwl RWL;
struct rwl {
sem_t lock;
sem_t wread;
sem_t wwrite;
int nreaders;
int nwriters;
};
void RWL_REnter(RWL *l) {
while (1) {
sem_wait(&l->lock);
l->nreaders++;
if (l->nwriters) {
sem_post(&l->lock);
sem_wait(&l->wread);
} else {
sem_post(&l->lock);
break;
}
}
}
void RWL_WEnter(RWL *l) {
while (1) {
sem_wait(&l->lock);
l->nwriters++;
if (l->nreaders || l->nwriters > 1) {
sem_post(&l->lock);
sem_wait(&l->wwrite);
} else {
sem_post(&l->lock);
break;
}
}
}
void RWL_WExit(RWL *l) {
sem_wait(&l->lock);
if (--(l->nwriters)) {
sem_post(&l->wwrite);
} else while (l->nreaders--) {
sem_post(&l->wread);
}
sem_post(&l->lock);
}
void RWL_RExit(RWL *l) {
sem_wait(&l->lock);
if (--(l->nreaders)) {
sem_post(&l->wread);
} else if (l->nwriters--) {
sem_post(&l->wwrite);
}
sem_post(&l->lock);
}
Functionally, lock is a mutex for the structure, and wwrite, wread serve as condition variables for the writers and readers respectively. nreaders is required to remember how many concurrent readers there are (since you can't wait on a +tive semaphore ) and nwriters for how many writers are waiting [ you don't want to post blindly in either condition ].

Two threads accessing a locked mutex simultaneously

I have written this code in C language and there are two pthreads that are using this code and trying to access the mutex "firstSection" (in both of them we are sure that the mutex passed to function is the same). The code suppose to check two mutexes, and if both of them were available, performs some actions which take place in function safeUnlockTwoMutexes(), and if failed to acquire at least one of them, it has to wait for two seconds and tries again. ("intersection" mutex is the main-lock to safe check the situation of the other mutexes)
void twoSectionRoute(pthread_mutex_t firstSection, pthread_mutex_t secondSection){
bool pathClear = false;
while (!pathClear){
pthread_mutex_lock(&intersection);
if (pthread_mutex_trylock(&firstSection) == 0){
if (pthread_mutex_trylock(&secondSection) == 0){
pathClear = true;
pthread_mutex_unlock(&intersection);
} else {
pthread_mutex_unlock(&firstSection);
pthread_mutex_unlock(&intersection);
sleep(2);
}
} else {
pthread_mutex_unlock(&intersection);
sleep(2);
}
}
safeUnlockTwoMutexes(firstSection, secondSection, 1);
}
Now the problem with this code is both threads are able to lock the mutex "firstSectio" at almost same time and I don't know why. (maybe because its type is recursive mutex?! I've used "PTHREAD_MUTEX_INITIALIZER" in the beginning of the file as global variables)
I'm wondering how can I fix this issue, and the threads access this sections one after another?
Your function signature passes pthread_mutex_t values firstSection and secondSection by value. You need to pass mutexes by pointer.
void twoSectionRoute(pthread_mutex_t* firstSection, pthread_mutex_t* secondSection){
Then, within the function use just firstSection and secondSection rather than &firstSection and &secondSection.
If you pass the mutex by value (as here), and it compiles, then the mutex itself is copied, so you end up with undefined behaviour and the mutex locks do not operate on the same state.

C Pthread: Kill other threads gracefully through one thread

I am working on a pthread problem in C.
The background of the problem: There are 5 threads using the same function, and when the core data in the shared memory hit the upper bound, all these five threads should terminate. I use semaphore to make sure only one of them executes the core data, which means only one of the five will get the end signal and then it will tell the rest to terminate. The code I wrote to achieve is:
#define THREAD_NUM 5;
int thread[THREAD_NUM];
sem_t s; /*semaphore to synchronize*/
sem_t empty; /*keep check of the number of empty buffers*/
sem_t full; /*keep check of the number of full buffers*/
void com_thread(*prt){ // I pass the id of the thread using prt
while(1){
sem_wait(&full)
sem_wait(&s)
...do something
sem_post(&s)
sem_post(&empty)
}
}
The signal will come while the while loop is running, and I tried to accept the signal at following position and then terminate all the threads.
To be honest, what I need to do is end all of the threads gracefully, and I need them to return to the main thread for thread_join() and free memory rather than simply exiting the program. So that's why I did not use exit() here.
The main idea below is terminating the other 4 threads when one of them got the signal. After that it would terminate itself.
However, it does not work as I expected.
#define THREAD_NUM 5;
int thread[THREAD_NUM];
sem_t s; /*semaphore to synchronize*/
sem_t empty; /*keep check of the number of empty buffers*/
sem_t full; /*keep check of the number of full buffers*/
void com_thread(*prt){ // I pass the id of the thread using prt
while(1){
sem_wait(&full)
sem_wait(&s)
if(signal){
int i;
int id = *((int*) prt);
for (i=0;i<THREAD_NUM;i++){
if(i != id)
pthread_exit(&thread[i]);
}
pthread_exit(&thread[id]);
}
...do something
sem_post(&s)
sem_post(&empty)
}
}
Can anyone help me with that? Or, if there is a better way to achieve this? Thanks in advance :)
You can use pthead_kill from the thread you want to terminate all other threads. Man page is at http://linux.die.net/man/3/pthread_kill. You should choose signal carefully if you want graceful termination. http://linux.die.net/man/7/signal has more details.
The easiest solution is probably to have a single global boolean variable, initially initialized to "false". All the threads check if this variable is "false" or "true", and if it's "true" they terminate.
When a single thread notices that all threads should be terminated it simply sets this flag to "true", and the other threads will notice that sooner or later.
You can check for this exit-condition in multiple places in the thread function, especially if some thread is waiting for a lock from the currently active thread (the one that sets the exit condition).

c semaphore sem_post max value to 0

I have a program where one thread runs a task, and when it can no longer run it based on a condition, it waits:
void thread1() {
while(...) {
if(can_do_stuff) {
//do stuff
}
else {
sem_wait(&sem);
}
}
}
This thread can be woken up by several other threads (each performing a separate task that can lead to a reason for thread1 to be woken up) by calling sem_post:
void threadx() {
while(...) {
if(need_thread1_to_run) {
sem_post(&sem);
}
else {
//do stuff
}
}
}
However, the problem with this is that whenever thread1 calls sem_wait, it needs to wait, which basically means that the maximum value that the semaphore should have is 0. So ideally, if it was already at 0 and a thread called sem_post, the value would not change. Is there anyway to do this with semaphores in C? If not, is there another synchronization method in C that could do this better? I thought that the threads could call sem_getvalue before calling sem_post to see if the value was already 0, but that would not be thread safe and I think two threads could still both call sem_post at the same time. I also thought that condition variables could be a possibility, but those require a mutex and I don't really need a mutex for this, so I was hoping there was something simpler.

Producer/Consumer in C with pthread semaphores and multiple threads

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);
}

Resources