Last active
October 24, 2024 08:30
-
-
Save pedrominicz/ce45ee016ac067701e54b72fd03f1888 to your computer and use it in GitHub Desktop.
Peterson's algorithm in C.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <pthread.h> | |
#include <unistd.h> | |
#include <stdarg.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
// This program illustrates the use of Peterson's algorithm to synchronize | |
// multiple threads.Two new threads are created and alternate writing to the | |
// standard output. | |
// | |
// The key difference between Peterson's algorithm and strict alternation is | |
// the inclusion of flags indicating whether a thread is ready to enter the | |
// critical section. | |
// This function is taken from `http://git.suckless.org/dwm/file/util.c.html`. | |
// | |
// Print the error message and `perror` if the message ends in `':'`. Assumes | |
// `fmt` is not `NULL`. | |
void die(const char* fmt, ...) { | |
va_list ap; | |
va_start(ap, fmt); | |
vfprintf(stderr, fmt, ap); | |
va_end(ap); | |
// Following Unix convention (see `man perror`), first check if the string is | |
// not empty. | |
if(fmt[0] && fmt[strlen(fmt) - 1] == ':') { | |
fputc(' ', stderr); | |
perror(NULL); | |
} else { | |
fputc('\n', stderr); | |
} | |
exit(0); | |
} | |
// The `turn` variable indicates which thread should enter the critical | |
// section. Unlike strict alternation, the `turn` variable is set _before_ | |
// entering the critical section. | |
// | |
// Note that globally-scoped variables are initialized to zero. | |
int turn; | |
int flag[2]; | |
void* f0(void* arg) { | |
while(1) { | |
// Signal that this thread wants to enter the critical section. | |
flag[0] = 1; | |
// Signal to the other thread that it is their turn. | |
turn = 1; | |
while(flag[1] && turn == 1); | |
puts("hello"); | |
flag[0] = 0; | |
sleep(1); | |
} | |
} | |
void* f1(void* arg) { | |
while(1) { | |
flag[1] = 1; | |
turn = 0; | |
while(flag[0] && turn == 0); | |
puts("world"); | |
flag[1] = 0; | |
sleep(1); | |
} | |
} | |
int main(void) { | |
// A POSIX thread has two main components: an object of type `pthread_t` | |
// which represents the thread and a function pointer of type | |
// `void* (*)(void*)` which will be the entry point of the thread. | |
pthread_t t0, t1; | |
// Creates new threads. The second argument is a pointer to a | |
// `pthread_attr_t`, if `NULL` the thread is created with default attributes. | |
// The last argument is the argument that is given to the thread's entry | |
// point function, unused in this example. | |
if(pthread_create(&t0, NULL, f0, NULL)) die("unable to create thread"); | |
if(pthread_create(&t1, NULL, f1, NULL)) die("unable to create thread"); | |
// Yes, I could have just created one thread. | |
while(1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment