Skip to content

Instantly share code, notes, and snippets.

@tbelaire
Created November 4, 2012 18:19
Show Gist options
  • Save tbelaire/4012855 to your computer and use it in GitHub Desktop.
Save tbelaire/4012855 to your computer and use it in GitHub Desktop.
A small concurrent C example
#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