Skip to main content
deleted 16 characters in body; edited title
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

pthread_cond_wait() based multithreaded linuxLinux daemon skeleton in c

The main thread then performs some global state management and some lite processing that I'm willing to restrict to the main thread (like mysqlMySQL stuff). After that the main thread defers the processing to a pool of worker threads.

Here's my code. I haven't posted the logging and much of the error checking code here. I'm planning on using the start-stop-daemon facility for daemonizing.

pthread_cond_wait() based multithreaded linux daemon skeleton in c

The main thread then performs some global state management and some lite processing that I'm willing to restrict to the main thread (like mysql stuff). After that the main thread defers the processing to a pool of worker threads.

Here's my code. I haven't posted the logging and much of the error checking code here. I'm planning on using the start-stop-daemon facility for daemonizing.

pthread_cond_wait() based multithreaded Linux daemon skeleton

The main thread then performs some global state management and some lite processing that I'm willing to restrict to the main thread (like MySQL stuff). After that the main thread defers the processing to a pool of worker threads.

I haven't posted the logging and much of the error checking code here. I'm planning on using the start-stop-daemon facility for daemonizing.

Source Link

pthread_cond_wait() based multithreaded linux daemon skeleton in c

I'm trying to design a multithreaded daemon for an industrial automation related project.

The daemon will be using a number of 3rd party libs like MQTT, mysql, etc.. My idea is to have worker threads (or callbacks registered with these 3rd party libs) relay events to the main thread using a global mutex and conditional variable based synchronisation mechanism.

The main thread then performs some global state management and some lite processing that I'm willing to restrict to the main thread (like mysql stuff). After that the main thread defers the processing to a pool of worker threads.

Here's my code. I haven't posted the logging and much of the error checking code here. I'm planning on using the start-stop-daemon facility for daemonizing.

I wanted to know if I'm headed in the right direction. Constructive criticism is welcome.

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

#define RESPONSE_MAX_LENGTH 256
/**
 * Internal data structures and enums
 */
typedef struct myThread_     {
    pthread_t id;
} myThreadT;

typedef enum myEventType_ {
    MY_EVENT_TYPE_NONE,
    MY_EVENT_TYPE_STOP,
    MY_EVENT_TYPE_RELOAD
} myEventTypeT;

typedef struct myEvent_ {
    int is_triggered;
    myEventTypeT type;
    void *data;        /* may include a callback */
} myEventT;

const myEventT myEventInitializer = {
        .is_triggered = 0,
        .type = MY_EVENT_TYPE_NONE,
        .data = NULL
};

/**
 * Global variables
 */
static myEventT myEvent;
static myThreadT worker;
/* Mutex and cond_var */
static pthread_mutex_t my_event_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  my_event_trigger_cv = PTHREAD_COND_INITIALIZER;

/*
 * Triggers an internal myEvent
 * Blocks calling thread till event acknowledgement
*/
int trigger_event(myEventTypeT type, void *data) {
    pthread_mutex_lock(&my_event_mutex);
    myEvent.type = type;
    myEvent.data = data;
    // Trigger event!
    myEvent.is_triggered = 1;
    pthread_cond_signal(&my_event_trigger_cv);
    pthread_mutex_unlock(&my_event_mutex);
    // Block till current trigger has been acknowledged
    while(myEvent.is_triggered);
    return 0;
}

void *worker_loop() {
    while(1) {
        sleep(5);       /* Do something worthwhile */
        trigger_event(MY_EVENT_TYPE_NONE, NULL);
    }
    pthread_exit(NULL);
}

/*
 * Called from main thread, mainly for state management & db related processing,
 * i.e. stuff we want to restrict to the main thread.
*/
int handle_event(myEventT *event, char *response) {
    // handle the event, fill response if required
    return 0;
}

int main(int argc, char* argv[]) {
    // Initialize globals
    myEvent = myEventInitializer;

    // Thread management
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    int thread_error;
    thread_error = pthread_create(&worker.id, &attr, worker_loop, NULL);
    if (thread_error != 0) {
        return -1;
    }

    pthread_attr_destroy(&attr);
    pthread_mutex_lock(&my_event_mutex);

    // Main loop: wait for event
    while(1) {

        // Wait for signal from worker threads/ callbacks
        int res_wait = pthread_cond_wait(&my_event_trigger_cv, &my_event_mutex);
        if (res_wait == EINVAL) {   // TODO: Consolidated error handling
            return -1;
        }

        /**
         * Event handling construct
         *
         */
        if (myEvent.is_triggered) {
            pthread_mutex_unlock(&my_event_mutex);

            char response_string[RESPONSE_MAX_LENGTH];  //TODO macro for size!
            if(handle_event(&myEvent, response_string) >= 0) {
                // Initiate deferred processing on another thread (maybe callback)
            }

            // Clear event triggered flag and reinit event data
            myEvent = myEventInitializer;

            pthread_mutex_lock(&my_event_mutex);
        }
    }

    // Clean up pthread resources
    pthread_mutex_destroy(&my_event_mutex);
    pthread_cond_destroy(&my_event_trigger_cv);

    pthread_exit(NULL);
}