Channels in C

#include <stdio.h>
#include <pthread.h>
#include <string.h>

#define MAX_MSG_LEN 100

// Struct to represent our channel
typedef struct {
    char message[MAX_MSG_LEN];
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int ready;
} channel;

// Function to initialize the channel
void channel_init(channel *ch) {
    pthread_mutex_init(&ch->mutex, NULL);
    pthread_cond_init(&ch->cond, NULL);
    ch->ready = 0;
}

// Function to send a message through the channel
void channel_send(channel *ch, const char *msg) {
    pthread_mutex_lock(&ch->mutex);
    strcpy(ch->message, msg);
    ch->ready = 1;
    pthread_cond_signal(&ch->cond);
    pthread_mutex_unlock(&ch->mutex);
}

// Function to receive a message from the channel
void channel_receive(channel *ch, char *msg) {
    pthread_mutex_lock(&ch->mutex);
    while (!ch->ready) {
        pthread_cond_wait(&ch->cond, &ch->mutex);
    }
    strcpy(msg, ch->message);
    ch->ready = 0;
    pthread_mutex_unlock(&ch->mutex);
}

// Function for the sender thread
void *sender(void *arg) {
    channel *ch = (channel *)arg;
    channel_send(ch, "ping");
    return NULL;
}

int main() {
    channel ch;
    channel_init(&ch);

    // Create a new thread to send the message
    pthread_t thread;
    pthread_create(&thread, NULL, sender, &ch);

    // Receive the message in the main thread
    char msg[MAX_MSG_LEN];
    channel_receive(&ch, msg);
    printf("%s\n", msg);

    pthread_join(thread, NULL);
    return 0;
}

In this C translation, we’ve implemented a simple channel-like mechanism using POSIX threads (pthreads) and condition variables. Here’s a breakdown of the code:

  1. We define a channel struct that holds the message, a mutex for synchronization, a condition variable, and a ready flag.

  2. The channel_init function initializes the channel’s mutex and condition variable.

  3. channel_send sends a message through the channel by copying the message, setting the ready flag, and signaling the condition variable.

  4. channel_receive receives a message from the channel. It waits on the condition variable if the message isn’t ready yet.

  5. The sender function is the equivalent of the goroutine in the original example. It runs in a separate thread and sends the “ping” message.

  6. In main, we create the channel, start the sender thread, and then receive and print the message.

To compile and run this program:

$ gcc -o channels channels.c -lpthread
$ ./channels
ping

This C implementation mimics the behavior of the original example, using threads and condition variables to achieve a similar concurrency model. The sender thread sends a “ping” message, which is then received and printed by the main thread.

Note that while this implementation provides similar functionality, C doesn’t have built-in support for channels like Go does. This example uses lower-level primitives (mutexes and condition variables) to achieve similar behavior.