簡體   English   中英

C eventcounter + sequencer中的死鎖並發問題

[英]Deadlock concurrency issue in C eventcounter + sequencer

我正在嘗試使此代碼正常工作,但由於某種原因,它在30秒內陷入僵局。

無論緩沖區是否已滿,死鎖似乎都發生在Puting或Getting中。

我是否缺少明顯的東西或沒有使用正確的東西? 我是C的新手!

要編譯:gcc -Wall -o test test.c -lpthread

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>



struct sequence {
    pthread_mutex_t mutex;
    int count;
};

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

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



/**
 * Issue tickets in sequence. Used in conjunction with an Event Counter
 */
int getTicket(struct sequence *seq) {
    // begin critical section
    if (pthread_mutex_lock(&seq->mutex) != 0) {
        printf("mutex_lock in getticket error\n");
    }

    // remember current count
    int oldCount = seq->count;

    // increment count
    seq->count++;

    // end critical section
    if (pthread_mutex_unlock(&seq->mutex) != 0) {
        printf("mutex_unlock in getticket error\n");
    }

    return oldCount;
}



/**
 * Advance the EventCount (ticket)
 */
void advance(struct event *event) {
    // begin critical section
    if (pthread_mutex_lock(&event->critical) != 0) {
        fprintf(stderr, "mutex_lock in advance error\n");
        exit(EXIT_FAILURE);
    }

    // increment the event counter
    event->eventCount++;

    // end critical section
    if (pthread_mutex_unlock(&event->critical) != 0) {
        fprintf(stderr, "mutex_unlock in advance error\n");
        exit(EXIT_FAILURE);
    }

    // signal await to continue
    if (pthread_cond_signal(&event->signalC) != 0) {
        fprintf(stderr, "cond_signal in advance error\n");
        exit(EXIT_FAILURE);
    }
}



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

    int eventCount;

    // begin critical section
    if (pthread_mutex_lock(&event->critical) != 0) {
        fprintf(stderr, "mutex_lock in advance error\n");
        exit(EXIT_FAILURE);
    }

    eventCount = event->eventCount;

    // end critical section
    if (pthread_mutex_unlock(&event->critical) != 0) {
        fprintf(stderr, "mutex_unlock in advance error\n");
        exit(EXIT_FAILURE);
    }


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

        // begin critical section
        if (pthread_mutex_lock(&event->critical) != 0) {
            fprintf(stderr, "mutex_lock in advance error\n");
            exit(EXIT_FAILURE);
        }

        eventCount = event->eventCount;

        // end critical section
        if (pthread_mutex_unlock(&event->critical) != 0) {
            fprintf(stderr, "mutex_unlock in advance error\n");
            exit(EXIT_FAILURE);
        }
    }
}



/**
 * Add to buffer
 */
void putBuffer(struct allVars *allVars, char data[]) {
    // get a ticket
    int ticket = getTicket(&allVars->putSeq);

    // get the current write position
    int in;

    // begin critical section
    if (pthread_mutex_lock(&allVars->inEvents.critical) != 0) {
        fprintf(stderr, "mutex_lock in put error\n");
        exit(EXIT_FAILURE);
    }

    in = allVars->inEvents.eventCount;

    // end critical section
    if (pthread_mutex_unlock(&allVars->inEvents.critical) != 0) {
        fprintf(stderr, "mutex_unlock in put error\n");
        exit(EXIT_FAILURE);
    }

    // wait for ticket to be called (sequential writing)
    await(&allVars->inEvents, ticket);

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

    // begin critical section
    if (pthread_mutex_lock(&allVars->inEvents.critical2) != 0) {
        fprintf(stderr, "mutex_lock in put error\n");
        exit(EXIT_FAILURE);
    }

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

    // end critical section
    if (pthread_mutex_unlock(&allVars->inEvents.critical2) != 0) {
        fprintf(stderr, "mutex_unlock in put error\n");
        exit(EXIT_FAILURE);
    }

    // increment the ticket display
    advance(&allVars->inEvents);
}



/**
 * Get from buffer
 */
char *getBuffer(struct allVars *allVars) {
    // get a ticket
    int ticket = getTicket(&allVars->getSeq);

    // get the current read position
    int out;

    // begin critical section
    if (pthread_mutex_lock(&allVars->outEvents.critical) != 0) {
        fprintf(stderr, "mutex_lock in get error\n");
        exit(EXIT_FAILURE);
    }

    out = allVars->outEvents.eventCount;

    // end critical section
    if (pthread_mutex_unlock(&allVars->outEvents.critical) != 0) {
        fprintf(stderr, "mutex_unlock in get error\n");
        exit(EXIT_FAILURE);
    }

    // wait for ticket to be called (sequential reading)
    await(&allVars->outEvents, ticket);

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

    char *str = malloc(128);

    // critical section
    if (pthread_mutex_lock(&allVars->inEvents.critical2) != 0) {
        fprintf(stderr, "mutex_lock in put error\n");
        exit(EXIT_FAILURE);
    }

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

    // end critical section
    if (pthread_mutex_unlock(&allVars->inEvents.critical2) != 0) {
        fprintf(stderr, "mutex_unlock in put error\n");
        exit(EXIT_FAILURE);
    }

    // increment buffer availability
    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 sequence putSeq = {
        PTHREAD_MUTEX_INITIALIZER,
        0
    };
    struct sequence getSeq = {
        PTHREAD_MUTEX_INITIALIZER,
        0
    };
    struct event inEvents = {
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_COND_INITIALIZER,
        0
    };
    struct event outEvents = {
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_MUTEX_INITIALIZER,
        PTHREAD_COND_INITIALIZER,
        0
    };
    struct allVars allVars = {
        putSeq,         // sequence
        getSeq,
        inEvents,       // events
        outEvents,
        10,             // buffersize
        {"", {""}}      // buffer[][]
    };
    pthread_mutex_lock(&allVars.inEvents.signalM);
    pthread_mutex_lock(&allVars.outEvents.signalM);


    // 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);
}

我不確定這是否是您的問題的根源,但這是肯定會導致鎖定問題的一個錯誤:

您使用的pthread_cond_waitpthread_cond_signal錯誤。 在調用pthread_cond_waitpthread_cond_signal之前,應始終鎖定條件的互斥鎖。

pthread_cond_wait調用后會自動為您釋放互斥鎖,並在發出信號后重新獲取該互斥鎖。 因此,您必須在發出線程信號后釋放鎖。

當我在大學學習pthread編程課程時, 此pthread編程教程對我有很大幫助。 我建議您看一下它,因為它也涵蓋了pthread編程的其他方面(例如互斥體)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM