Skip to content

Instantly share code, notes, and snippets.

@michael-grunder
Created September 22, 2021 17:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michael-grunder/f834736189963f131f43ccd7bfeeb49c to your computer and use it in GitHub Desktop.
Save michael-grunder/f834736189963f131f43ccd7bfeeb49c to your computer and use it in GitHub Desktop.
Tiny example using libevent and hiredis
// cc -Wall -ggdb3 -O0 -o example example.c -lhiredis -levent -lpthread -levent_pthreads
#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <pthread.h>
#include <hiredis/async.h>
#include <hiredis/adapters/libevent.h>
#include <event2/thread.h>
static redisAsyncContext *ac;
static char *message;
struct event_base *base;
void setCallback(redisAsyncContext *ac, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) {
if (ac->errstr) {
printf("errstr: %s\n", ac->errstr);
}
return;
}
assert(reply->type == REDIS_REPLY_STATUS);
printf("SET result: %s\n", reply->str);
free(privdata);
}
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}
void *eventThread(void *arg) {
struct event_base *base = arg;
event_base_dispatch(base);
return NULL;
}
void sigCb(evutil_socket_t fd, short what, void *arg) {
if (message != NULL) {
printf("sigCb: Executing SET foo %s\n", message);
redisAsyncCommand(ac, setCallback, message, "SET foo %s", message);
} else {
printf("sigCb: NULL payload, exiting loop\n");
event_base_loopbreak(base);
}
}
int main(void) {
pthread_t thread;
struct event *ev_signal;
redisOptions options = {0};
char buffer[255], *newline;
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
ac = redisAsyncConnectWithOptions(&options);
assert(ac != NULL && !ac->err);
base = event_base_new();
evthread_use_pthreads();
if (evthread_make_base_notifiable(base)<0) {
printf("Couldn't make base notifiable!");
return 1;
}
/* Let's add our own event so we can signal the loop */
ev_signal = event_new(base, -1, EV_PERSIST, sigCb, "SET event");
redisLibeventAttach(ac, base);
redisAsyncSetConnectCallback(ac, connectCallback);
assert(pthread_create(&thread, NULL, eventThread, base) == 0);
while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
assert((newline = strchr(buffer, '\n')) != NULL);
*newline = '\0';
if (!strcmp(buffer, "quit")) {
message = NULL;
printf("Exiting loop...\n");
event_active(ev_signal, 0, 0);
break;
}
/* NOTE: This is completely unsafe, you would want to use some
kind of thread-safe queue to pass the message payload */
message = strdup(buffer);
event_active(ev_signal, 0, 0);
}
assert(pthread_join(thread, NULL) == 0);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment