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