Last active
June 5, 2024 06:49
-
-
Save Geal/8f85e02561d101decf9a to your computer and use it in GitHub Desktop.
small future and promise library in C with pthreads
This file contains hidden or 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 <stdio.h> | |
#include <stdlib.h> | |
#include <pthread.h> | |
#include <unistd.h> | |
#include <stdbool.h> | |
#include <time.h> | |
#include <stdarg.h> | |
#include <string.h> | |
#include "future.h" | |
future* future_create(void *(*start_routine) (void *)) { | |
future* f = malloc(sizeof(future)); | |
pthread_attr_init(&f->attr); | |
pthread_attr_setdetachstate(&f->attr, PTHREAD_CREATE_JOINABLE); | |
f->func = start_routine; | |
srand(time(NULL)); | |
f->id = rand(); | |
return f; | |
} | |
void* future_func_wrapper(void *arg) { | |
//msg("WRAP"); | |
future_arg* f = (future_arg*) arg; | |
void* res = f->func(f->arg); | |
free(f); | |
//msg("WRAPPED"); | |
pthread_exit(res); | |
return res; | |
} | |
void future_start(future* f, void* arg) { | |
future_arg* farg = malloc(sizeof(future_arg)); | |
farg->func = f->func; | |
farg->arg = arg; | |
pthread_create(&f->thread, &f->attr, future_func_wrapper, farg); | |
} | |
void future_stop(future* f) { | |
pthread_cancel(f->thread); | |
} | |
void future_close(future* f) { | |
void * status; | |
int rc = pthread_join(f->thread, &status); | |
pthread_attr_destroy(&f->attr); | |
free(f); | |
} | |
promise* promise_create() { | |
promise* p = malloc(sizeof(promise)); | |
pthread_mutex_init(&p->mutex, NULL); | |
pthread_cond_init(&p->cond, NULL); | |
srand(time(NULL)); | |
p->id = rand(); | |
msg("P(%d) created", p->id); | |
return p; | |
} | |
void promise_set(promise* p, int res) { | |
msg("P(%d) set LOCK", p->id); | |
pthread_mutex_lock(&p->mutex); | |
p->result = res; | |
p->done = true; | |
pthread_cond_signal(&p->cond); | |
msg("P(%d) set UNLOCK", p->id); | |
pthread_mutex_unlock(&p->mutex); | |
} | |
int promise_get(promise* p) { | |
msg("P(%d) get LOCK", p->id); | |
pthread_mutex_lock(&p->mutex); | |
while(!p->done) { | |
msg("P(%d) get WAIT", p->id); | |
pthread_cond_wait(&p->cond, &p->mutex); | |
} | |
msg("P(%d) get UNLOCK", p->id); | |
pthread_mutex_unlock(&p->mutex); | |
return p->result; | |
} | |
bool promise_done(promise* p) { | |
pthread_mutex_lock(&p->mutex); | |
bool done = p->done; | |
pthread_mutex_unlock(&p->mutex); | |
return done; | |
} | |
void promise_close(promise* p) { | |
pthread_mutex_destroy(&p->mutex); | |
pthread_cond_destroy(&p->cond); | |
free(p); | |
} |
This file contains hidden or 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 <stdbool.h> | |
typedef struct _future { | |
pthread_t thread; | |
pthread_attr_t attr; | |
void *(*func) (void *); | |
} future; | |
typedef struct _future_arg { | |
void *(*func) (void *); | |
void * arg; | |
} future_arg; | |
typedef struct _promise { | |
int result; | |
pthread_mutex_t mutex; | |
pthread_cond_t cond; | |
bool done; | |
int id; | |
} promise; | |
future* future_create(void *(*start_routine) (void *)); | |
void future_start(future* f, void* arg); | |
void future_stop(future* f); | |
void future_close(future* f); | |
promise* promise_create(); | |
int promise_get(promise* p); | |
void promise_set(promise *p, int res); | |
bool promise_done(promise* p); | |
void promise_close(promise *p); | |
#ifdef DEBUG | |
#define msg(format, ...) printf("T(%d)|" format "\n", (int)pthread_self(), ##__VA_ARGS__) | |
#else | |
#define msg(format, ...)· | |
#endif |
This file contains hidden or 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 <stdio.h> | |
#include <stdlib.h> | |
#include <pthread.h> | |
#include <unistd.h> | |
#include <stdbool.h> | |
#include "future/future.h" | |
void* func(void * arg) { | |
promise* p = (promise*) arg; | |
printf("\tstarted thread\n"); | |
sleep(3); | |
printf("\tthread will set promise\n"); | |
promise_set(p, 42); | |
printf("\tstopping thread\n"); | |
return NULL; | |
} | |
int main() { | |
long t; | |
printf("main thread\n"); | |
future* f = future_create(func); | |
promise* p = promise_create(); | |
future_start(f, p); | |
printf("got result from future: %d\n", promise_get(p)); | |
promise_close(p); | |
future_close(f); | |
pthread_exit(NULL); | |
} |
What's this? Is this identical to the c++ std::future under the hood?
add a header guard:
#ifndef _FUTURE_H_
#define _FUTURE_H_
...
#endif /*_FUTURE_H_*/
to compile, should add "id" to the structure future:
typedef struct _future {
pthread_t thread;
pthread_attr_t attr;
void *(*func) (void *);
int id;
} future;
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
future_close(f)
should be called beforepromise_close(p)
, otherwise, deadlock might happen.