Skip to content

Instantly share code, notes, and snippets.

@Kaiepi
Last active May 7, 2021 02:53
Show Gist options
  • Save Kaiepi/e5ec7ca9dcdcfcaa14c2a721a7fe11de to your computer and use it in GitHub Desktop.
Save Kaiepi/e5ec7ca9dcdcfcaa14c2a721a7fe11de to your computer and use it in GitHub Desktop.
CSP in C. Build with `gcc -o csp csp.c -lpthread`
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
struct channel_node {
void *val;
struct channel_node *next;
struct channel_node *prev;
};
struct channel {
struct channel_node *head;
struct channel_node *tail;
sem_t mutex;
sem_t sent;
sem_t received;
};
struct channel *
channel_init(void)
{
struct channel *ch = malloc(sizeof(struct channel));
ch->head = NULL;
ch->tail = NULL;
sem_init(&ch->mutex, 0, 1);
sem_init(&ch->sent, 0, -1);
sem_init(&ch->received, 0, 0);
return ch;
}
void *
channel_recv(struct channel *ch)
{
sem_wait(&ch->mutex);
struct channel_node *node = ch->head;
void *msg = node->val;
if (ch->head == ch->tail) {
ch->head = NULL;
ch->tail = NULL;
} else {
ch->head = node->next;
}
free(node);
sem_post(&ch->received);
sem_post(&ch->mutex);
return msg;
}
void
channel_wait(struct channel *ch, size_t count)
{
size_t i;
for (i = 0; i < count; ++i) {
sem_wait(&ch->received);
sem_wait(&ch->sent);
}
}
void
channel_send(struct channel *ch, void *msg)
{
sem_wait(&ch->mutex);
struct channel_node *node = malloc(sizeof(struct channel_node));
node->val = msg;
node->prev = ch->tail;
node->next = NULL;
if (ch->head == NULL) {
ch->head = node;
ch->tail = node;
} else {
ch->tail->next = node;
ch->tail = node;
}
sem_post(&ch->sent);
sem_post(&ch->mutex);
}
size_t
channel_length(struct channel *ch)
{
sem_wait(&ch->mutex);
size_t len = 0;
struct channel_node *node = ch->head;
while (node != NULL) {
node = node->next;
++len;
}
sem_post(&ch->mutex);
return len;
}
void
channel_free(struct channel *ch)
{
if (ch->head != NULL) free(ch->head);
if (ch->tail != NULL) free(ch->tail);
sem_destroy(&ch->mutex);
sem_destroy(&ch->sent);
sem_destroy(&ch->received);
free(ch);
}
void *
pinger(void *p)
{
struct channel *ch = (struct channel *)p;
channel_send(ch, "ping");
channel_send(ch, "ping");
printf("Channel length is %zd\n", channel_length(ch));
channel_wait(ch, 2);
char *pong = channel_recv(ch);
printf("%s\n", pong);
pong = channel_recv(ch);
printf("%s\n", pong);
printf("Channel length is %zd\n", channel_length(ch));
pthread_exit(NULL);
return NULL;
}
void *
ponger(void *p)
{
struct channel *ch = (struct channel *)p;
char *ping = channel_recv(ch);
printf("%s\n", ping);
ping = channel_recv(ch);
printf("%s\n", ping);
channel_send(ch, "pong");
channel_send(ch, "pong");
pthread_exit(NULL);
return NULL;
}
int
main(void)
{
struct channel *ch = channel_init();
pthread_t t1, t2;
pthread_create(&t1, NULL, pinger, ch);
pthread_create(&t2, NULL, ponger, ch);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
channel_free(ch);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment