POSIX (unistd.h)
Forking a Process
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid;
/* for a child process */
pid = fork();
if (pid < 0) { /* error occured */
fprintf(stderr, "Fork failed");
return 1;
} else if (pid == 0) { /* child process */
execlp("/bin/ls", "ls", NULL);
} else { /* parent process */
/* parent will wait for the child to complete */
wait(NULL);
printf("Child Complete");
}
return 0;
}- Windows: nutzt
CreateProcess()undWaitForSingleObject() - Linux alternativ auch
spawn(), wenn kein MMU-Support vorhanden undfork()deshalb nicht unterstรผtztsystem(), um einen Shell-Command auszufรผhren
Interprocess Communication
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main() {
/* the size (in bytes) of shared memory object */
const int SIZE = 4096;
/* name of the shared memory object */
const char *name = "OS";
/* strings written to shared memory */
const char *message_0 = "Hello";
const char *message_1 = "World!";
/* shared memory file descriptor */
int shm_df;
/* pointer to shared memory object */
void *ptr;
/* create the shared memory object */
shm_fd = shm_open(name, O_CREAT | O_RDRW, 0666);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
/* memory map the shared memory object */
ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
/* write to the shared memory object */
sprintf(ptr, "%s", message_0);
ptr += strlen(message_0);
sprintf(ptr, "%s", message_1);
ptr += strlen(message_1);
return 0;
}#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main() {
/* the size (in bytes) of shared memory object */
const int SIZE = 4096;
/* name of the shared memory object */
const char *name = "OS";
/* shared memory file descriptor */
int shm_fd;
/* pointer to shared memory object */
void *ptr
/* open the shared memory object */
shm_fd = shm_open(name, O_RDONLY, 0666);
/* memory map the shared memory object */
ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
/* read from the shared memory object */
printf("%s", (char*)ptr);
/* remove the shared memory object */
shm_unlink(name);
return 0;
}Thread-Erstellung
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
int sum; /* this daza is shared by the thread(s) */
void *runner(void *param); /* threads call this function */
int main() {
pthread_t tid; /* the thread identifier */
pthread_attr_t attr; /* set of thread attributes */
/* set the default attributes of the thread */
pthread_attr_init(&attr);
/* create the thread */
pthread_create(&tid, &attr, runner, argv[1]);
/* wait for the thread to exit */
pthread_join(tid, NULL);
printf("sum = %d\n", sum);
}
/* the thread will execute this function */
void *runner(void *param) {
int i, upper = atoi(param);
sum = 0;
for (i = 1; i <= upper; i++)
sum += 1;
pthread_exit(0);
}- Windows:
CreateThread()undWaitForSingleObject() - Linux:
clone()mit FlagsCLONE_FS,CLONE_VM,CLONE_SIGHAND,CLONE_FILES
Joining multiple Threads
# define NUM_THREADS 10
/* an array of threads to be joind upon */
pthread_t workers[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++)
pthread_join(workers[i], NULL);Canceling a Thread
pthread_t tid;
/* create the thread */
pthread_create(&tid, 0, worker, NULL);
...
/* cancel the thread */
pthread_cancel(tid);
/* wait for the thread to terminate */
pthread_join(tid, NULL);Scheduling Scope
POSIX bietet die Mรถglichkeit, den Scheduling Scope (process-contention scope, system-contention scope) auszuwรคhlen
- mรถglich mittels
ptread_attr_getscope()undpthread_attr_setscope() - von Linux und macOS wird nur
PTHREAD_SCOPE_SYSTEMund nichtPTHREAD_SCOPE_PROCESSunterstรผtzt
Scheduling Policy
pthread_attr_getschedpolicy()undpthread_attr_setschedpolicy()SCHED_FIFO,SCHED_RRund system-spezifischesSCHED_OTHER
Mutex locks
#include <pthread.h>
pthread_mutex_t mutex;
/* create and initialize the mutex lock */
pthread_mutex_init(&mutex, NULL);/* acquire the mutex lock */
pthread_mutex_lock(&mutex);
/* critial section */
/* release the mutex lock */
pthread_mutex_unlock(&mutex);Semaphoren
- POSIX stellt zwei Varianten zur Verfรผgung: unnamed (nur verwandte Prozesse) und named (beliebige Prozesse)
#include <semaphore.h>
/* create unnamed semaphore and initialize it to 1 */
sem_t sem;
sem_init(&sem, 0, 1);
/* create named semaphore and initialize it to 1 */
sem_t *sem;
sem = sem_open("SEM", O_CREAT, 0666, 1);/* acquire the semaphore */
sem_wait(&sem); // named just sem
/* critical section */
/* release the semaphore */
sem_post(&sem); // named just semCondition Variablen
pthread_mutex_t mutex;
pthread_cond_t cond_var;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond_var, NULL);
/* thread waiting for the condition a == b to become true */
pthread_mutex_lock(&mutex);
while (a != b)
pthread_cond_wait(&cond_var, &mutex);
pthread_mutex_unlock(&mutex);
/* thread signaling another thread waiting on the condition variable */
pthread_mutex_lock(&mutex);
a = b;
pthread_cond_signal(&cond_var);
pthread_mutex_unlock(&mutex);Synchronisation Examples
Bounded Buffer
- Buffers, jeder kann ein Item halten
- Semaphore
mutex, die auf initialisiert ist - Semaphore
full, die auf initialisiert ist - Semaphore
empty, die auf initialisiert ist
while (true) {
/* produce an item in next_produced */
wait(empty);
wait(mutex);
/* add next produced to the buffer */
signal(mutex);
signal(full);
}while (true) {
wait(full);
wait(mutex);
/* remove an item from buffer to next_consumed */
signal(mutex);
signal(empty);
/* consume the item in next consumed */
}Readers-Writers Problem
- Datensatz
- Semaphore
rw_mutex, die auf initialisiert ist - Semaphore
mutex, die auf initialisiert ist - Integer
read_count, der auf initialisiert ist
while (true) {
wait(rw_mutex);
/* writing is performed */
signal(rw_mutex);
}while (true){
wait(mutex);
read_count++;
if (read_count == 1) /* first reader */
wait(rw_mutex);
signal(mutex);
/* reading is performed */
wait(mutex);
read_count--;
if (read_count == 0) /* last reader */
signal(rw_mutex);
signal(mutex);
}Dining Philosophers
Semaphoren
while (true){
wait (chopstick[i] );
wait (chopStick[ (i + 1) % 5] );
/* eat for awhile */
signal (chopstick[i] );
signal (chopstick[ (i + 1) % 5] );
/* think for awhile */
}Monitor
monitor DiningPhilosophers
{
enum {THINKING; HUNGRY, EATING} state [5];
condition self [5];
void pickup (int i) {
state[i] = HUNGRY;
test(i);
if (state[i] != EATING) self[i].wait;
}
void putdown (int i) {
state[i] = THINKING;
// test left and right neighbors
test((i + 4) % 5);
test((i + 1) % 5);
}
void test (int i) {
if ((state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING) ) {
state[i] = EATING ;
self[i].signal () ;
}
}
initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}- der Philosoph ruft erst
DiningPhilosophers.pickup(i)und dann irgendwann โDininigPhilosophers.putdown(i)` auf
Systemaufrufe
Aufgaben auf Blatt 1 nach relevanten Themen durchsuchen