Semaphores
An Introduction |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
sem_t *sem_open(const char *name, int oflag, /* mode_t mode, unsigned value */)
name
|
The name of the semaphore |
oflag
|
A flag that controls the opening (see below) |
mode
|
O_RDONLY, O_WRONLY, or O_RDWR (required iff O_CREAT is set) |
value
|
Required only O_CREAT is set |
Return | The handle for the semaphore on success; SEM_FAILED on error |
O_CREAT
is used to create a semaphore. O_CREAT
& O_EXCL
is used to create a semaphore but fail if it
already exists.
NAME_MAX - 4
characterssem_t
valueint sem_close(sem_t *sem)
sem
|
The handle to the semaphore |
Return | 0 on success; -1 on error |
Note that sem_close()
does not delete the semaphore.
ls -l /dev/shm/sem.*
EINTR
(regardless of whther the SA_RESTART
flag
was used when the signal handler was installed/established)sem_wait()
-pthread
#include <fcntl.h> // For O_CREAT #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { pid_t pid; sem_t *done; // Call open() in the original process so that we don't have to // worry about coordinating the call to open() done = sem_open("/done", O_CREAT, O_RDWR, 0); pid = fork(); switch(pid) { case -1: exit(1); case 0: // Child write(STDOUT_FILENO, "Task 1\n", 7); sem_post(done); // Increment the semaphore sem_close(done); exit(0); default: // Parent sem_wait(done); // Try to decrement the semaphore write(STDOUT_FILENO, "Task 2\n", 7); sem_close(done); sem_unlink("/done"); write(STDOUT_FILENO, "\nCheck: ls -l /dev/shm/sem.* \n", 30); exit(0); } }
#include <fcntl.h> #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include "../signals/tax_lib.h" int main(void) { float rate, sales, tax; int should, status; pid_t pid; sem_t *alert; rate = 0.05; alert = sem_open("/alert", O_CREAT, O_RDWR, 0); pid = fork(); switch(pid) { case -1: exit(1); case 0: if (should_tax()) sem_post(alert); // Increment (i.e., alert the child) sem_close(alert); exit(0); default: sales = total_sales(); // Reap the child (waiting for it to finish) wait(&status); // See whether the child "alerted". This function will return -1 // if the semaphore can't be decremented immediately should = sem_trywait(alert); if (should == -1) tax = 0.0; // The child didn't "alert" else tax = sales * rate; // The child "alert" printf("Tax: %5.2f\n", tax); sem_close(alert); sem_unlink("/alert"); exit(0); } }
Note: The "sender" transmits one bit of information (as in the similar examples that used signals and pipes) by either incrementing the semaphore or not.
wait()
#include <fcntl.h> #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include "../signals/tax_lib.h" int main(void) { float rate, sales, tax; int should, status; pid_t pid; sem_t *alert, *done; rate = 0.05; alert = sem_open("/alert", O_CREAT, O_RDWR, 0); done = sem_open("/done", O_CREAT, O_RDWR, 0); pid = fork(); switch(pid) { case -1: exit(1); case 0: // "Alert" the child if necessary if (should_tax()) sem_post(alert); // In either case, indicate that the calculation is done sem_post(done); record_status(); // This takes a long time // Close the semaphores sem_close(alert); sem_close(done); exit(0); default: sales = total_sales(); // Try to decrement the semaphore and wait (until the child is done) // if it isn't possible sem_wait(done); // See whether the child "alerted". This function will return -1 // if the semaphore can't be decremented immediately should = sem_trywait(alert); if (should == -1) tax = 0.0; // The child didn't "alert" else tax = sales * rate; // The child "alert" printf("Tax: %5.2f\n", tax); // Reap the child (waiting for it to finish) wait(&status); // Close and unlink the semaphores sem_close(alert); sem_unlink("/alert"); sem_close(done); sem_unlink("/done"); exit(0); } }
Note: One semaphore is being used to satisfy the sequencing constraint and another is being used for "alerting".
#include <fcntl.h> // For O_CREAT #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { pid_t pid; sem_t *conch; // The semaphore is named conch in a reference to "Lord of the Flies" // by William Golding (you had to have the conch to talk) conch = sem_open("/conch", O_CREAT, O_RDWR, 1); // The initial value is 1 pid = fork(); switch(pid) { case -1: exit(1); case 0: // Child sem_wait(conch); // Try to decrement the semaphore // Start of Critical Section write(STDOUT_FILENO, "Ralph \n", 7); // End of Critical Section sem_post(conch); // Increment the semaphore sem_close(conch); exit(0); default: // Parent sem_wait(conch); // Try to decrement the semaphore // Start of Critical Section write(STDOUT_FILENO, "Piggy \n", 7); // End of Critical Section sem_post(conch); // Increment the semaphore sem_close(conch); sem_unlink("/conch"); write(STDOUT_FILENO, "\nCheck: ls -l /dev/shm/sem.* \n", 30); exit(0); } }
Note: The semaphore is initialized to 1 so that whichever process checks first can "enter".