Semaphores and mutexes in linux

Building semaphores using Mutexes

When implmented with a semaphore this looks fine: However, if I do the same thing with a mutex ( which is technically a binary semaphore ), it has an odd code smell. Solution 2: Since you have a case to use a semaphore, I think the fix is to portably implement one using a mutex and a condition variable.

Building semaphores using Mutexes

I’m reading Modern Operating Systems and there’s a exercise that asks you to build a counting-semaphore with a binary-semaphore.

I was wondering if I could do it with semaphores & shared memory (C and posix ipc).

I’ll leave a simplification of my program here.

typedef struct sem < int semid; /* contains two semaphores with value set to 1, one for the critical region and the other for locking */ int shmid; /* shared counter */ >Sem; /* the parent process spawns a few child processes and then waits for them */ void child() < Sem *s; s = get_sem(); down_sem(s); printf("working. "); sleep(5); printf("finished!"); up_sem(s); >void down_sem(Sem *s) < int n; enter_critical(s); // down to critical region sem n = get_counter(s); if (n == 0) < exit_critical(s); // up to critical region sem acquire_lock(s); // down to lock sem >else < n--; exit_critical(s); // up to critical region sem >> void up_sem(Sem *s) < int n; enter_critical(s); n = get_counter(s); n++; if (n == 1) < exit_critical(s); release_lock(s); // up to lock sem >else < exit_critical(s); >> 

But this doesn’t work since some processes block in the lock semaphore forever. I’m just now learning these concepts so my design is probably totally off.

I can share the complete code if you wish.

EDIT: requested mre

#include #include #include #include #include #include #include #include #include #define NPROC 5 #define SLOTS 2 #define PATH "." #define SID 'S' #define SEMN 2 #define SHMID 'M' #define SHM_SIZE 32 #define CRIT 0 #define LOCK 1 #define UP 1 #define DOWN -1 typedef struct sem < int shmid; int semid; >Sem; typedef union semun < int val; struct semid_ds *buf; unsigned short *array; >Args; void err (char *msg) < char error[50]; int n; n = snprintf(error, 50, "[%d] %s", getpid(), msg); error[n] = 0; perror(error); exit(1); >int* get_n(Sem *s) < int *data = NULL; data = shmat(s->shmid, (void *)0, 0); if (data == (int *)(-1)) err("get_n shmat"); return data; > void dettach_n(int *data) < if (shmdt(data) == -1) err("dettach_n shmdt"); >void enter_crit(Sem *s) < struct sembuf sb; sb.sem_num = CRIT; sb.sem_op = DOWN; printf("[%d] enter crit\n", getpid()); if (semop(s->semid, &sb, 1) == -1) err("enter crit"); > void exit_crit(Sem *s) < struct sembuf sb; sb.sem_num = CRIT; sb.sem_op = UP; printf("[%d] exit crit\n", getpid()); if (semop(s->semid, &sb, 1) == -1) err("exit crit"); > void acquire_lock(Sem *s) < struct sembuf sb; sb.sem_num = LOCK; sb.sem_op = DOWN; printf("[%d] acquire lock\n", getpid()); if (semop(s->semid, &sb, 1) == -1) err("acquire lock"); > void release_lock(Sem *s) < struct sembuf sb; sb.sem_num = LOCK; sb.sem_op = UP; printf("[%d] release lock\n", getpid()); if (semop(s->semid, &sb, 1) == -1) err("release lock"); > int sem_init(Sem *s, int n) < key_t key; Args arg; int *data; /* sem */ if ((key = ftok(PATH, SID)) == -1) < return -1; >if ((s->semid = semget(key, SEMN, 0600 | IPC_CREAT)) == -1) < return -1; >arg.val = 1; if (semctl(s->semid, 0, SETVAL, arg) == -1) < return -1; >if (semctl(s->semid, 1, SETVAL, arg) == -1) < return -1; >/* mem */ if ((key = ftok(PATH, SHMID)) == -1) < return -1; >if ((s->shmid = shmget(key, SHM_SIZE, 0664 | IPC_CREAT)) == -1) < return -1; >data = shmat(s->shmid, (void *)0, 0); if (data == (int *)(-1)) < return -1; >*data = n; if (shmdt(data) == -1) < return -1; >return 0; > int sem_get(Sem *s) < key_t key; if ((key = ftok(PATH, SID)) == -1) < return -1; >if ((s->semid = semget(key, SEMN, 0)) == -1) < return -1; >if ((key = ftok(PATH, SHMID)) == -1) < return -1; >if ((s->shmid = shmget(key, SHM_SIZE, 0)) == -1) < return -1; >return 0; > int sem_up(Sem *s) < int *data; enter_crit(s); data = get_n(s); printf("[%d] read %d\n", getpid(), *data); (*data)++; if (*data == 1) < printf("[%d] now is %d\n", getpid(), *data); dettach_n(data); exit_crit(s); release_lock(s); >else < exit_crit(s); >return 0; > int sem_down(Sem *s) < int *data; enter_crit(s); data = get_n(s); printf("[%d] checked %d\n", getpid(), *data); if (*data == 0) < dettach_n(data); exit_crit(s); acquire_lock(s); >else < (*data)--; dettach_n(data); exit_crit(s); >return 0; > int sem_rm(Sem *s) < if (semctl(s->semid, 0, IPC_RMID) == -1) return -1; if (shmctl(s->shmid, 0, IPC_RMID) == -1) return -1; return 0; > void child() < pid_t pid; Sem s; pid = getpid(); printf("\x1b[31m[%d] hello!\033[0m\n", pid); if (sem_get(&s) == -1) < perror("sem_get"); exit(1); >sem_down(&s); printf("\x1b[32m[%d] working. \033[0m\n", pid); sleep(5); printf("\x1b[32m[%d] finishing. \033[0m\n", pid); sem_up(&s); printf("\x1b[34m[%d] **child leaving**\033[0m\n", pid); exit(0); > int main() < Sem s; int i; if (sem_init(&s, SLOTS) == -1) < perror("sem_init"); exit(1); >printf("[%d] parent\n", getpid()); for (i = 0; i < NPROC; i++) < switch(fork()) < case 0: child(); case -1: perror("fork"); exit(1); >> printf("waiting for children. \n"); for (i = 0; i < NPROC; i++) wait(NULL); if (sem_rm(&s) == -1) < perror("sem_rm"); exit(1); >printf("good bye!\n"); return 0; > 

The problem was in the up_sem function. It only does an up to the lock sem (release_lock func) if n was previously 0. This is incorrect since it might be several process waiting.

Читайте также:  Search for files find linux

My solution was adding an extra shared memory counting the waiting processes and doing an up to the lock sem when that number is greater than 0.

What are the practical uses of semaphores?, Non-binary semaphores are used in resource allocation. A semaphore might hold the count of the number of a particular resource. If you have a pool of connections, such as a web browser might use, then an individual thread might reserve a member of the pool by waiting on the semaphore to get a …

Use a mutex as a semaphore?

I need two threads to progress in a «tick tock» pattern. When implmented with a semaphore this looks fine:

Semaphore tick_sem(1); Semaphore tock_sem(0); void ticker( void ) < while( true ) < P( tick_sem ); do_tick(); V( tock_sem ); >> void tocker( void ) < while( true ) < P( tock_sem ); do_tock(); V( tick_sem ); >> 

However, if I do the same thing with a mutex ( which is technically a binary semaphore ), it has an odd code smell.

std::mutex tick_mutex; std::mutex tock_mutex; tock_mutex.lock(); void ticker( void ) < while( true ) < tick_mutex.lock(); do_tick(); tock_mutex.unlock(); >> void tocker( void ) < while( true ) < tock_mutex.lock() do_tock(); tick_mutex.unlock(); >> 

I think the smell is that a mutex isn’t meant to convey information to another thread. (The c++11 standard committee added a spurious fail to try_lock to defeat unexpected information transfer; §30.4.1/14.) It seems like mutexes are meant to synchronize access to a variable, which can then convey information to another thread.

Lastly, when implemented with a std::condition_variable , it looks correct but it’s more complicated ( a tick_vs_tock variable, a mutex, and a condition variable). I’ve omitted the implementation for brevity, but it’s really straight forward.

Читайте также:  Изменение времени создания файла linux

Is the mutex solution fine? Or is there something subtly wrong with it?

Is there a good pattern for solving my tick/tock problem that I haven’t thought of?

A Mutex is not simply just a binary semaphore, it also has the limitation that only the locking thread is allowed to unlock it.

You are breaking that rule.

The releasemutex function fails if the calling thread does not own the mutex object.

From some site that google turned up for pthread_mutex_unlock:

The pthread_mutex_unlock() function may fail if:

EPERM The current thread does not own the mutex.

And you will find the same on other mutex implementations. It makes sense because a mutex is supposed to guard a thread’s access to a resource, so another thread should not be able to unlock it.

Since you have a case to use a semaphore, I think the fix is to portably implement one using a mutex and a condition variable.

This might not be especially efficient (since it’ll use a mutex/condvar pair per semaphore), but you can switch in an alternate implementation on systems that have their own semaphores (such as Posix and Windows).

Apparently semaphores are «too error-prone». With all due respect to Boost, I think at least some of us can manage. Certainly you can tie yourself in knots trying to do complicated things with multiple semaphores, and they are a pretty low-level tool. But when they’re the right thing, no problem.

Operating system — Dining savages problem, I’ve encountered the dining savages problem and solution, but I don’t seem to understad how the solution is handling the situation when a savage tries to eat from the pot while it’s still empty. The

Читайте также:  Select c socket linux

Semaphores and Mutex for Thread and Process Synchronization

I am confused with the usage of semaphores and mutexes at thread and process level. Can we use semphores and mutexes for both thread and process synchronization, or do we have different semaphores and mutexes both at thread and process level? My question is with reference to the POSIX API’s.

The answer to both questions is yes. You can create both mutexes and semaphores as either process-shared or not. So you can use them as interprocess or interthread synchronization objects, but you have to specify which when you create them.

Of course, you must create the synchronization object in memory that is shared by all contexts that wish to access it. With threads, that’s trivial since they share a view of memory. With processes, you have to create the synchronization object in shared memory specifically.

Synchronization protects elements when they share data or when their tasks must be ordered.

Processes and threads basically are the same (with differences) they are pieces of computation that make some work, the only thing you have to pay attention is when you are working with processes and when with threads but the method used is the same.

C Using Mutexes & Semaphores to create a Blocking, Building semaphores using Mutexes. Hot Network Questions Are there any Japanese fonts with a similar style to the English font «Diploma Regular» When exactly are IMMEDIATE constraints checked and what exactly is a «statement» in Postgres?

Semaphore and mutex, which one is faster?

If you consider a binary semaphore and mutex, which one is faster? I mean, takes less instructions. What additional data does mutex maintain compared to semaphore?

This is implementation dependent, but you will probably find that mutex has been implemented to be slightly faster. Mutexes are typically implemented with test and set, while semaphores are often implemented with test and increment or as a mutex guarding a variable that is incremented.

I would suggest using a mutex in most cases, but not due to speed; simply because code written using mutexes is easier to understand as the semantics are less complicated.

Multithreading — What is the difference between, To synchronize threads across process boundaries, use mutexes. To synchronize access to limited resources, use a semaphore. Apart from the fact that mutexes have an owner, the two objects may be optimized for different usage. Mutexes are designed to be held only for a short time; violating this can cause …

Источник

Оцените статью
Adblock
detector