Skip to content

Instantly share code, notes, and snippets.

@sitano
Created October 21, 2021 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sitano/bcd52ebb25eff044c0ecd03990452d05 to your computer and use it in GitHub Desktop.
Save sitano/bcd52ebb25eff044c0ecd03990452d05 to your computer and use it in GitHub Desktop.
experimenting with cond signal and ruby scheduler
#define _MULTI_THREADED
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
/* For safe condition variable usage, must use a boolean predicate and */
/* a mutex with the condition. */
int acquired = 0;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#define NTHREADS 5
void check(const char *str, int err) {
if (err)
printf("[%d] err=%d: %s", gettid(), err, str);
}
void acq(int id) {
check("lock()", pthread_mutex_lock(&mutex));
while (acquired) {
printf("[%d] %d: wait\n", gettid(), id);
check("pthread_cond_wait()\n", pthread_cond_wait(&cond, &mutex));
}
printf("[%d] %d: acq\n", gettid(), id);
acquired = 1;
check("unlock()", pthread_mutex_unlock(&mutex));
}
void rel(int id) {
check("lock()", pthread_mutex_lock(&mutex));
printf("[%d] %d: rel\n", gettid(), id);
acquired = 0;
pthread_cond_signal(&cond);
check("unlock()", pthread_mutex_unlock(&mutex));
}
void *threadfunc(void *parm) {
char buf[4096];
while (1) {
acq((int)parm);
int fd = open("/dev/null", "w");
if (!fd) {
printf("bad bad bad: %s\n", strerror(errno));
}
for (int i = 0; i < 1000; i ++) {
write(fd, buf, 4096);
}
close(fd);
rel((int)parm);
}
return NULL;
}
int main(int argc, char **argv) {
int rc=0;
int i;
pthread_t threadid[NTHREADS];
printf("Create %d threads\n", NTHREADS);
for(i=0; i<NTHREADS; ++i) {
check("pthread_create()", pthread_create(&threadid[i], NULL, threadfunc, (i+1)));
}
while (1) {
sleep(1);
}
return 0;
}
@sitano
Copy link
Author

sitano commented Oct 21, 2021

output:

[16664] 1: acq
[16666] 3: wait
[16664] 1: rel
[16664] 1: acq
[16667] 4: wait
[16664] 1: rel
[16664] 1: acq
[16668] 5: wait
[16664] 1: rel
[16664] 1: acq
[16665] 2: wait
[16664] 1: rel
[16664] 1: acq
[16666] 3: wait
[16664] 1: rel
[16664] 1: acq
[16667] 4: wait
[16664] 1: rel
[16664] 1: acq

acquisitions only by 1 thread
so that Ruby also can't reschedule until winning thread waits on separate yield cond

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment