Rate Limiting in C

Our rate limiting implementation uses a simple timer approach with sleep functions to control the rate of execution. We’ll use POSIX threads to simulate concurrent execution.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>

#define REQUESTS 5
#define BURST_SIZE 3

void *process_requests(void *arg);
void *bursty_limiter(void *arg);

int main() {
    pthread_t thread1, thread2;

    // Process regular requests
    pthread_create(&thread1, NULL, process_requests, NULL);
    pthread_join(thread1, NULL);

    // Process bursty requests
    pthread_create(&thread2, NULL, bursty_limiter, NULL);
    pthread_join(thread2, NULL);

    return 0;
}

void *process_requests(void *arg) {
    for (int i = 1; i <= REQUESTS; i++) {
        usleep(200000);  // Sleep for 200 milliseconds
        printf("request %d %ld\n", i, time(NULL));
    }
    return NULL;
}

void *bursty_limiter(void *arg) {
    int bursty_requests[REQUESTS] = {1, 2, 3, 4, 5};

    for (int i = 0; i < REQUESTS; i++) {
        if (i < BURST_SIZE) {
            printf("request %d %ld\n", bursty_requests[i], time(NULL));
        } else {
            usleep(200000);  // Sleep for 200 milliseconds
            printf("request %d %ld\n", bursty_requests[i], time(NULL));
        }
    }
    return NULL;
}

This C implementation simulates rate limiting using the following approach:

  1. We define two functions: process_requests and bursty_limiter.

  2. The process_requests function simulates basic rate limiting by processing requests with a 200-millisecond delay between each request.

  3. The bursty_limiter function simulates bursty rate limiting. It processes the first three requests immediately (simulating the burst), then adds a 200-millisecond delay for the remaining requests.

  4. In the main function, we create two threads to run these functions concurrently.

To compile and run the program:

$ gcc -o rate_limiting rate_limiting.c -lpthread
$ ./rate_limiting

The output will show the first batch of requests handled once every ~200 milliseconds:

request 1 1621234567
request 2 1621234567
request 3 1621234567
request 4 1621234568
request 5 1621234568

For the second batch (bursty requests), you’ll see the first 3 processed immediately, followed by the remaining 2 with ~200ms delays:

request 1 1621234568
request 2 1621234568
request 3 1621234568
request 4 1621234568
request 5 1621234569

Note that this C implementation is a simplified version of the rate limiting concept. In a real-world scenario, you might want to use more sophisticated timing mechanisms and consider thread-safety issues.

The C language doesn’t have built-in constructs for channels or tickers like Go, so we’ve simulated these concepts using sleep functions and POSIX threads. This approach gives a basic understanding of rate limiting, although it’s not as elegant or precise as the Go implementation.