Created
November 4, 2012 18:19
-
-
Save tbelaire/4012855 to your computer and use it in GitHub Desktop.
A small concurrent C example
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 <stdlib.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
// Small channel library here. | |
// It mimics unbuffered Go channels. | |
typedef struct chan_int { | |
int message; | |
int full; // 1 -> Full | |
pthread_mutex_t mutex; | |
pthread_cond_t on_read; | |
pthread_cond_t on_write; | |
} chan_int; | |
int chan_int_init(chan_int * c){ | |
c->message = 0; | |
c->full = 0; | |
if (pthread_mutex_init(&(c->mutex), NULL)){ | |
return 1;} | |
if (pthread_cond_init(&(c->on_read), NULL)){ | |
return 1;} | |
if (pthread_cond_init(&(c->on_write), NULL)){ | |
return 1;} | |
return 0; | |
} | |
int chan_int_destroy(chan_int * c){ | |
if(pthread_cond_destroy(&(c->on_write))){ | |
return 1;} | |
if(pthread_cond_destroy(&(c->on_read))){ | |
return 1;} | |
if(pthread_mutex_destroy(&(c->mutex))){ | |
return 1;} | |
return 0; | |
} | |
/* | |
* Semantics: | |
* write to empty chan does block | |
* write to full chan does block | |
* read from empty chan does block | |
* read from full chan does not block | |
*/ | |
void chan_int_write(chan_int * c, int message){ | |
pthread_mutex_lock(&c->mutex); | |
// Wait for it to be read before filling it again. | |
if(c->full){ | |
pthread_cond_wait(&(c->on_read), &(c->mutex)); | |
} | |
c->message = message; | |
c->full = 1; | |
pthread_mutex_unlock(&c->mutex); | |
pthread_cond_signal(&(c->on_write)); | |
// If we stopped here, it does not block on write to empty | |
pthread_mutex_lock(&c->mutex); | |
if(c->full){ | |
//Nobody has read it yet, wait for a read. | |
pthread_cond_wait(&c->on_read, &c->mutex); | |
} | |
// Once someone has read, we just return | |
pthread_mutex_unlock(&c->mutex); | |
} | |
int chan_int_read(chan_int * c){ | |
int msg; | |
pthread_mutex_lock(&c->mutex); | |
if(!c->full){ | |
// We must wait for a message if it's not full | |
pthread_cond_wait(&(c->on_write), &(c->mutex)); | |
// We know know that it is full | |
} | |
msg = c->message; | |
c->full = 0; | |
pthread_mutex_unlock(&(c->mutex)); | |
pthread_cond_signal(&(c->on_read)); | |
return msg; | |
} | |
// Main file here | |
#define OK 1 | |
#define QUIT 2 | |
void* hello(chan_int *c){ | |
for(int i = 0; i < 1000; i++){ | |
printf("Hello "); | |
chan_int_write(c, OK); | |
} | |
chan_int_write(c,QUIT); | |
return NULL; | |
} | |
void* world(chan_int *c){ | |
for(;;){ | |
int msg = chan_int_read(c); | |
if(msg == QUIT){ | |
break; | |
} else if( msg == OK){ | |
printf("World! \n"); | |
} | |
} | |
return NULL; | |
} | |
int main(){ | |
pthread_t hello_id, world_id; | |
chan_int chan; | |
chan_int_init(&chan); | |
if (pthread_create( &hello_id, NULL, hello, (void*)&chan)){ | |
printf("Error making thread hello"); | |
abort(); | |
} | |
if (pthread_create( &world_id, NULL, world, (void*)&chan)){ | |
printf("Error making thread world"); | |
abort(); | |
} | |
if (pthread_join( hello_id, NULL) || pthread_join( world_id, NULL)){ | |
printf("Error join threads"); | |
abort(); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment