Use of semaphores in read/write threads - c

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 ].

Related

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.

How should I simulate sem_wait with a count?

I'm using semaphore.h and would like to acquire a semaphore if n instead of just one slot is available. Posix does not provide this natively. How can I work around that? I'm bound to using semaphores, no other means of synchronization are possible.
I'm pondering using a binary semaphore with a separate counter variable, but that would, in my opinion, kind of defeat its purpose.
Since you have multiple threads contending for slots of the semaphore (else you wouldn't need semaphores at all), you need to protect against deadlock. For example, if your semaphore has four slots, and each of two threads is trying to acquire three, then they will deadlock if each manages to acquire two. It follows that you must protect access to the process of acquiring semaphore slots.
A binary semaphore protecting a counter is not sufficient to prevent the deadlock scenario described above. Moreover, if not enough slots are available at any given time then you must have some synchronous means to wait for more slots to become available. You can do the job with two semaphores, though, one to protect access to the semaphore acquisition process, and another carrying the actual slots being acquired. Something like this, for example:
#define DO_OR_RETURN(x) do { int _r; if ((_r = (x))) return _r; } while (0)
typedef struct multi_sem {
sem_t sem_acquire_sem;
sem_t multislot_sem;
} multisem;
int multisem_init(multisem *ms, unsigned int slots) {
DO_OR_RETURN(sem_init(&ms->sem_acquire_sem, 0, 1));
return sem_init(&ms->multislot_sem, 0, slots);
}
int multisem_wait(multisem *ms, unsigned int slots_to_acquire) {
int result;
DO_OR_RETURN(sem_wait(&ms->sem_acquire_sem));
while (slots_to_acquire) {
result = sem_wait(&ms->multislot_sem);
switch (result) {
case 0:
slots_to_acquire -= 1;
break;
case EINTR:
/* interrupted by a signal; try again */
break;
default:
/* undocumented error - should never happen */
/* insert appropriate apocalypse response here */
slots_to_acquire = 0; /* bail out */
break;
}
}
if (sem_post(&ms->sem_acquire_sem)) {
/* big oops - no recovery possible - should never happen */
/* insert appropriate apocalypse response here */
}
return result;
}
int multisem_post(multisem *ms, unsigned int slots_to_post) {
while (slots_to_post) {
DO_OR_RETURN(sem_post(&ms->multislot_sem));
slots_to_post -= 1;
}
return 0;
}
Do note that that is still susceptible to deadlock in the event that a thread tries to acquire slots of the multisem when it already holds at least one (among other ways). I think that risk is inherent in the problem.

C solution for producer-consumer with only ONE semaphore

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

Sharing data between master thread and slave thread in interrupt driven environment in C

I have the following:
f1()
{
while(1)
{
call f(2) if hardware interrupt pin goes high
}
}
f2()
{
if( th() not started )
{
start thread th()
}
else
{
return thread th() status
}
}
th()
{
time-consuming operation
}
At the moment, I use the following to initiate a struct in f2():
static struct SharedData shared;
if( shared == NULL)
{
initialize shared
}
Then I pass a pointer to shared to the thread. The thread then updates shared periodically. f2() will then know if th() has been started based on elements of shared and it will check the status of th() by reading from shared.
Let's assume one of the elements of shared is a mutex to provide thread safety. Is this a good solution? Is there a more elegant way of doing this? I have tested the code and it works. I just need some expert advice here.
Thanks,
Assuming that f2() uses the same mutex in the shared structure to lock before reading the data that the thread th uses to modify the data, I don't see any issues.
If you have more than one thread calling f2(), you may want to use a read-write lock for reading and writing of the thread status of th. The mutex could still be used to serialize the thread creation check. You could also use a pthread_rwlock_wrlock() to serialize th creation, but the code is arguably less clear.
Using a mutex to serialize th creation in f2():
pthread_rwlock_rdlock(&shared.rwlock);
result = shared.th_status;
if (! shared.th_created) {
pthread_mutex_lock(&shared.mutex);
if (! shared.th_created) {
pthread_create(...);
shrared.th_created = 1;
}
pthread_mutex_unlock(&shared_mutex);
}
pthread_rwlock_unlock(&shared.rwlock);
return result;
Using the read-write lock to serialize th creation in f2():
pthread_rwlock_rdlock(&shared.rwlock);
result = shared.th_status;
if (! shared.th_created) {
pthread_rwlock_unlock(&shared.rwlock);
pthread_rwlock_wrlock(&shared.rwlock);
if (! shared.th_created) {
pthread_create(...);
shrared.th_created = 1;
}
}
pthread_rwlock_unlock(&shared.rwlock);
return result;

Recreate sem_wait() with mutex?

Is there any way so I can have up to 10 threads in the same mutex?
Something like sem_wait() with value 10.
Edit:
Found this:
it is an implementation of semaphores, using mutexes and condition variables.
typedef struct {
int value, wakeups;
Mutex *mutex;
Cond *cond;
} Semaphore;
// SEMAPHORE
Semaphore *make_semaphore (int value)
{
Semaphore *semaphore = check_malloc (sizeof(Semaphore));
semaphore->value = value;
semaphore->wakeups = 0;
semaphore->mutex = make_mutex ();
semaphore->cond = make_cond ();
return semaphore;
}
void sem_wait (Semaphore *semaphore)
{
mutex_lock (semaphore->mutex);
semaphore->value--;
if (semaphore->value < 0) {
do {
cond_wait (semaphore->cond, semaphore->mutex);
} while (semaphore->wakeups < 1);
semaphore->wakeups--;
}
mutex_unlock (semaphore->mutex);
}
void sem_signal (Semaphore *semaphore)
{
mutex_lock (semaphore->mutex);
semaphore->value++;
if (semaphore->value <= 0) {
semaphore->wakeups++;
cond_signal (semaphore->cond);
}
mutex_unlock (semaphore->mutex);
}
See If that Helps
From Book Begining Linux programming a counting semaphore that
takes a wider range of values. Normally,semaphores are used to
protect a piece of code so that only one thread of execution can run
it at any one time. For this job a binary semaphore is needed.
Occasionally, you want to permit a limited number of threads to
execute a given piece of code; for this you would use a counting
semaphore
No, A mutex is a simple lock, having two states: locked and unlocked. When it is created, a mutex is unlocked. A mutex is a mutual exclusion lock. Only one thread can hold the lock.
Although you can implement to allow ten threads to enter in a section using mutex and if and a global variable. (the way count semaphores are implemented)
Read here: Implementing a Counting Semaphore
One Available implementation: C code , Make your own semaphore

Resources