C uninitialized mutex operation and initialized mutex fail?

My C creates a flow of manufacturers by storing data as quickly as possible. The main thread consumes and prints them.

After several days of detecting errors, I noticed that if the mutex was initialized, the program stops for 30 seconds (deadlock?).

However, if the mutex is left uninitialized, it works fine.

Can someone explain this? To avoid undefined behavior, I would prefer to initialize them if possible.

Additional information: In particular, it is blocked if "pthread_mutex_t signalM" (signal mutex) is initialized

Initialized

#include <stdlib.h>                     // exit_failure, exit_success
#include <stdio.h>                      // stdin, stdout, printf
#include <pthread.h>                    // threads
#include <string.h>                     // string
#include <unistd.h>                     // sleep
#include <stdbool.h>                    // bool
#include <fcntl.h>                      // open



struct event {
    pthread_mutex_t critical;
    pthread_mutex_t signalM;
    pthread_cond_t signalC;
    int eventCount;
};

struct allVars {
    struct event inEvents;
    struct event outEvents;
    int bufferSize;
    char buffer[10][128];
};




/**
 * Advance the EventCount
 */
void advance(struct event *event) {
    // increment the event counter
    pthread_mutex_lock(&event->critical);
    event->eventCount++;
    pthread_mutex_unlock(&event->critical);

    // signal await to continue
    pthread_mutex_lock(&event->signalM);
    pthread_cond_signal(&event->signalC);
    pthread_mutex_unlock(&event->signalM);
}



/**
 * Wait for ticket and buffer availability
 */
void await(struct event *event, int ticket) {

    int eventCount;

    // get the counter
    pthread_mutex_lock(&event->critical);
    eventCount = event->eventCount;
    pthread_mutex_unlock(&event->critical);

    // lock signaling mutex
    pthread_mutex_lock(&event->signalM);

    // loop until the ticket machine shows your number
    while (ticket > eventCount) {
        // wait until a ticket is called
        pthread_cond_wait(&event->signalC, &event->signalM);

        // get the counter
        pthread_mutex_lock(&event->critical);
        eventCount = event->eventCount;
        pthread_mutex_unlock(&event->critical);
    }

    // unlock signaling mutex
    pthread_mutex_unlock(&event->signalM);
}



/**
 * Add to buffer
 */
void putBuffer(struct allVars *allVars, char data[]) {
    // get the current write position
    pthread_mutex_lock(&allVars->inEvents.critical);
    int in = allVars->inEvents.eventCount;
    pthread_mutex_unlock(&allVars->inEvents.critical);

    // wait until theres a space free in the buffer
    await(&allVars->outEvents, in - allVars->bufferSize + 1);   // set to 2 to keep 1 index distance

    // add data to buffer
    strcpy(allVars->buffer[in % allVars->bufferSize], data);

    // increment the eventCounter and signal
    advance(&allVars->inEvents);
}



/**
 * Get from buffer
 */
char *getBuffer(struct allVars *allVars) {
    // get the current read position
    pthread_mutex_lock(&allVars->outEvents.critical);
    int out = allVars->outEvents.eventCount;
    pthread_mutex_unlock(&allVars->outEvents.critical);

    // wait until theres something in the buffer
    await(&allVars->inEvents, out + 1);

    // allocate memory for returned string
    char *str = malloc(128);

    // get the buffer data
    strcpy(str, allVars->buffer[out % allVars->bufferSize]);

    // increment the eventCounter and signal
    advance(&allVars->outEvents);

    return str;
}



/** child thread (producer) */
void *childThread(void *allVars) {
    char str[10];
    int count = 0;

    while (true) {
        sprintf(str, "%d", count++);
        putBuffer(allVars, str);
    }

    pthread_exit(EXIT_SUCCESS);
}



int main(void) {
    // init structs
    struct event inEvents = {
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_COND_INITIALIZER,
        0
    };
    struct event outEvents = {
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_COND_INITIALIZER,
        0
    };
    struct allVars allVars = {
        inEvents,       // events
        outEvents,
        10,             // buffersize
        {"", {""}}      // buffer[][]
    };


    // create child thread (producer)
    pthread_t thread;
    if (pthread_create(&thread, NULL, childThread, &allVars)) {
        fprintf(stderr, "failed to create child thread");
        exit(EXIT_FAILURE);
    }


    // (consumer)
    while (true) {
        char *out = getBuffer(&allVars);
        printf("buf: %s\n", out);
        free(out);
    }


    return (EXIT_SUCCESS);
}

Uninitialized

#include <stdlib.h>                     // exit_failure, exit_success
#include <stdio.h>                      // stdin, stdout, printf
#include <pthread.h>                    // threads
#include <string.h>                     // string
#include <unistd.h>                     // sleep
#include <stdbool.h>                    // bool
#include <fcntl.h>                      // open



struct event {
    pthread_mutex_t critical;
    pthread_mutex_t signalM;
    pthread_cond_t signalC;
    int eventCount;
};

struct allVars {
    struct event inEvents;
    struct event outEvents;
    int bufferSize;
    char buffer[10][128];
};




/**
 * Advance the EventCount
 */
void advance(struct event *event) {
    // increment the event counter
    pthread_mutex_lock(&event->critical);
    event->eventCount++;
    pthread_mutex_unlock(&event->critical);

    // signal await to continue
    pthread_mutex_lock(&event->signalM);
    pthread_cond_signal(&event->signalC);
    pthread_mutex_unlock(&event->signalM);
}



/**
 * Wait for ticket and buffer availability
 */
void await(struct event *event, int ticket) {

    int eventCount;

    // get the counter
    pthread_mutex_lock(&event->critical);
    eventCount = event->eventCount;
    pthread_mutex_unlock(&event->critical);

    // lock signaling mutex
    pthread_mutex_lock(&event->signalM);

    // loop until the ticket machine shows your number
    while (ticket > eventCount) {
        // wait until a ticket is called
        pthread_cond_wait(&event->signalC, &event->signalM);

        // get the counter
        pthread_mutex_lock(&event->critical);
        eventCount = event->eventCount;
        pthread_mutex_unlock(&event->critical);
    }

    // unlock signaling mutex
    pthread_mutex_unlock(&event->signalM);
}



/**
 * Add to buffer
 */
void putBuffer(struct allVars *allVars, char data[]) {
    // get the current write position
    pthread_mutex_lock(&allVars->inEvents.critical);
    int in = allVars->inEvents.eventCount;
    pthread_mutex_unlock(&allVars->inEvents.critical);

    // wait until theres a space free in the buffer
    await(&allVars->outEvents, in - allVars->bufferSize + 1);   // set to 2 to keep 1 index distance

    // add data to buffer
    strcpy(allVars->buffer[in % allVars->bufferSize], data);

    // increment the eventCounter and signal
    advance(&allVars->inEvents);
}



/**
 * Get from buffer
 */
char *getBuffer(struct allVars *allVars) {
    // get the current read position
    pthread_mutex_lock(&allVars->outEvents.critical);
    int out = allVars->outEvents.eventCount;
    pthread_mutex_unlock(&allVars->outEvents.critical);

    // wait until theres something in the buffer
    await(&allVars->inEvents, out + 1);

    // allocate memory for returned string
    char *str = malloc(128);

    // get the buffer data
    strcpy(str, allVars->buffer[out % allVars->bufferSize]);

    // increment the eventCounter and signal
    advance(&allVars->outEvents);

    return str;
}



/** child thread (producer) */
void *childThread(void *allVars) {
    char str[10];
    int count = 0;

    while (true) {
        sprintf(str, "%d", count++);
        putBuffer(allVars, str);
    }

    pthread_exit(EXIT_SUCCESS);
}



int main(void) {
    // init structs
    struct event inEvents; /* = {
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_COND_INITIALIZER,
        0
    }; */
    struct event outEvents; /* = {
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_COND_INITIALIZER,
        0
    }; */

    struct allVars allVars = {
        inEvents,       // events
        outEvents,
        10,             // buffersize
        {"", {""}}      // buffer[][]
    };


    // create child thread (producer)
    pthread_t thread;
    if (pthread_create(&thread, NULL, childThread, &allVars)) {
        fprintf(stderr, "failed to create child thread");
        exit(EXIT_FAILURE);
    }


    // (consumer)
    while (true) {
        char *out = getBuffer(&allVars);
        printf("buf: %s\n", out);
        free(out);
    }


    return (EXIT_SUCCESS);
}
+4
source share
2

, , , ( , , ).

, , , , . , . , , . , , "" ( ) .

, , event->eventCount , , .

, , . , signalM struct event critical:

#include <stdlib.h>                     // exit_failure, exit_success
#include <stdio.h>                      // stdin, stdout, printf
#include <pthread.h>                    // threads
#include <string.h>                     // string
#include <unistd.h>                     // sleep
#include <stdbool.h>                    // bool
#include <fcntl.h>                      // open



struct event {
    pthread_mutex_t critical;
    pthread_cond_t signalC;
    int eventCount;
};

struct allVars {
    struct event inEvents;
    struct event outEvents;
    int bufferSize;
    char buffer[10][128];
};




/**
 * Advance the EventCount
 */
void advance(struct event *event) {
    // increment the event counter
    pthread_mutex_lock(&event->critical);
    event->eventCount++;
    pthread_mutex_unlock(&event->critical);

    // signal await to continue
    pthread_cond_signal(&event->signalC);
}



/**
 * Wait for ticket and buffer availability
 */
void await(struct event *event, int ticket) {


    // get the counter
    pthread_mutex_lock(&event->critical);

    // loop until the ticket machine shows your number
    while (ticket > event->eventCount) {
        // wait until a ticket is called
        pthread_cond_wait(&event->signalC, &event->critical);
    }

    // unlock signaling mutex
    pthread_mutex_unlock(&event->critical);
}



/**
 * Add to buffer
 */
void putBuffer(struct allVars *allVars, char data[]) {
    // get the current write position
    pthread_mutex_lock(&allVars->inEvents.critical);
    int in = allVars->inEvents.eventCount;
    pthread_mutex_unlock(&allVars->inEvents.critical);

    // wait until theres a space free in the buffer
    await(&allVars->outEvents, in - allVars->bufferSize + 1);   // set to 2 to keep 1 index distance

    // add data to buffer
    strcpy(allVars->buffer[in % allVars->bufferSize], data);

    // increment the eventCounter and signal
    advance(&allVars->inEvents);
}



/**
 * Get from buffer
 */
char *getBuffer(struct allVars *allVars) {
    // get the current read position
    pthread_mutex_lock(&allVars->outEvents.critical);
    int out = allVars->outEvents.eventCount;
    pthread_mutex_unlock(&allVars->outEvents.critical);

    // wait until theres something in the buffer
    await(&allVars->inEvents, out + 1);

    // allocate memory for returned string
    char *str = malloc(128);

    // get the buffer data
    strcpy(str, allVars->buffer[out % allVars->bufferSize]);

    // increment the eventCounter and signal
    advance(&allVars->outEvents);

    return str;
}



/** child thread (producer) */
void *childThread(void *allVars) {
    char str[10];
    int count = 0;

    while (true) {
        sprintf(str, "%d", count++);
        putBuffer(allVars, str);
    }

    pthread_exit(EXIT_SUCCESS);
}



int main(void) {
    // init structs
    struct event inEvents = {
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_COND_INITIALIZER,
        0
    };
    struct event outEvents = {
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_COND_INITIALIZER,
        0
    };
    struct allVars allVars = {
        inEvents,       // events
        outEvents,
        10,             // buffersize
        {"", {""}}      // buffer[][]
    };


    // create child thread (producer)
    pthread_t thread;
    if (pthread_create(&thread, NULL, childThread, &allVars)) {
        fprintf(stderr, "failed to create child thread");
        exit(EXIT_FAILURE);
    }


    // (consumer)
    while (true) {
        char *out = getBuffer(&allVars);
        printf("buf: %s\n", out);
        free(out);
    }


    return (EXIT_SUCCESS);
}
+3

getBuffer() putBuffer(), ( , ):

static
void putBuffer(struct allVars *allVars, char data[])
{
    int lock_ok = pthread_mutex_lock(&allVars->inEvents.critical);
    if (lock_ok != 0)
        printf("%s(): lock error %d (%s)\n", __func__, lock_ok, strerror(lock_ok));
    int in = allVars->inEvents.eventCount;
    int unlock_ok = pthread_mutex_unlock(&allVars->inEvents.critical);
    if (unlock_ok != 0)
        printf("%s(): unlock error %d (%s)\n", __func__, unlock_ok, strerror(unlock_ok));

    await(&allVars->outEvents, in - allVars->bufferSize + 1);

    strcpy(allVars->buffer[in % allVars->bufferSize], data);

    advance(&allVars->inEvents);
}

static
char *getBuffer(struct allVars *allVars)
{
    int lock_ok = pthread_mutex_lock(&allVars->outEvents.critical);
    if (lock_ok != 0)
        printf("%s(): lock error %d (%s)\n", __func__, lock_ok, strerror(lock_ok));
    int out = allVars->outEvents.eventCount;
    int unlock_ok = pthread_mutex_unlock(&allVars->outEvents.critical);
    if (unlock_ok != 0)
        printf("%s(): unlock error %d (%s)\n", __func__, unlock_ok, strerror(unlock_ok));

    await(&allVars->inEvents, out + 1);

    char *str = malloc(128);

    strcpy(str, allVars->buffer[out % allVars->bufferSize]);

    advance(&allVars->outEvents);

    return str;
}

, :

buf: 46566
putBuffer(): lock error 22 (Invalid argument)
getBuffer(): lock error 22 (Invalid argument)
putBuffer(): unlock error 22 (Invalid argument)
getBuffer(): unlock error 22 (Invalid argument)

, , . , .

, , , , , .

, .

, . , Mac OS X 10.10.3 GCC 5.1.0, 100 000 800 000 .

+2

All Articles