2016-03-21 6 views
0

Ich habe das folgende Programm erstellt, um einen Protokollierungsthread zu erstellen und anderen Threads zu ermöglichen, in einen gemeinsam genutzten Puffer zu schreiben, der von diesem Thread verwaltet wird. Seltsamerweise, wenn ich kein Schreiben in das Protokoll in meiner stopLog Funktion einschließe, wird das Protokoll nie geschlossen und der Thread wird nicht beendet.Seltsames Verhalten des Logging-Threads

#include "log.h" 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <pthread.h> 

#define BUFFER_SIZE 128 

static pthread_mutex_t logFileMutex = PTHREAD_MUTEX_INITIALIZER; 
static pthread_mutex_t logInUse = PTHREAD_MUTEX_INITIALIZER; 
static pthread_cond_t emptyCond = PTHREAD_COND_INITIALIZER; 
static pthread_cond_t fullCond = PTHREAD_COND_INITIALIZER; 
static int bufferIsEmpty; 
static int bufferIsFull; 
static char buffer[BUFFER_SIZE]; 
static int in; 
static int out; 
static int count; 
static int stop; 

void * logOutput(void * in) { 
    stop = 0; 
    bufferIsEmpty = 1; 
    bufferIsFull = 0; 
    char ch; 
    FILE * f = fopen((char *)in, "a"); 
    if (NULL != f) { 
     fprintf(f, "---------------- Log Opened ----------------\n"); 
     while (!stop) { 
      pthread_mutex_lock(&logFileMutex); 
      while (bufferIsEmpty) 
       pthread_cond_wait(&emptyCond, &logFileMutex); 
      ch = buffer[out++]; 
      out %= BUFFER_SIZE; 
      if (--count == 0) 
       bufferIsEmpty = 1; 
      bufferIsFull = 0; 
      fputc(ch, f); 
      pthread_cond_signal(&fullCond); 
      pthread_mutex_unlock(&logFileMutex); 
     } 
     fprintf(f, "---------------- Log Closed ----------------\n"); 
     fflush(f); 
     fclose(f); 
    } else { 
     fprintf(stderr, "Error opening log file %s\n", (char *)in); 
    } 
    pthread_exit(NULL); 
} 

void writeToLog(char * str) { 
    pthread_mutex_lock(&logInUse); 
    for (int i = 0; i <= strlen(str); i++) { 
     pthread_mutex_lock(&logFileMutex); 
     while (bufferIsFull) 
      pthread_cond_wait(&fullCond, &logFileMutex); 
     if (strlen(str) == i) 
      buffer[in++] = '\n'; 
     else 
      buffer[in++] = str[i]; 
     in %= BUFFER_SIZE; 
     if (++count == (BUFFER_SIZE - 1)) 
      bufferIsFull = 1; 
     bufferIsEmpty = 0; 
     usleep(10); 
     pthread_cond_signal(&emptyCond); 
     pthread_mutex_unlock(&logFileMutex); 
    } 
    pthread_mutex_unlock(&logInUse); 
} 

void stopLog() { 
    writeToLog("Stopping log..."); 
    stop = 1; 
} 
+0

Dies wird Ihr Problem nicht lösen, aber 'logOutput' gibt ein' void * 'zurück, hat aber keine Rückgabeanweisungen. –

+0

@ cormac-obrien Das ist in Ordnung - es ist ein Pthread, also pthread_exit kümmert sich um die tatsächliche Rückkehr –

+0

Es ist in der Regel eine gute Idee, eine sowieso zur Verfügung zu stellen - wenn Sie nichts zurückgeben müssen, nur zurück "NULL". Wird eine Compiler-Warnung los, wenn nichts anderes. –

Antwort

1

Wenn der Puffer leer ist und logOutput() auf pthread_cond_wait() blockiert wird, stop = 1 Einstellung ist es nicht mehr aufwachen würde. Es wird nicht bemerken, bis es das nächste Mal aufwacht, und das Schreiben einiger logarithmischer Ausgaben führt das durch.

Als Variable, die zwischen Threads geteilt wird, muss stop auch vor unsynchronisierten Zugriffen geschützt werden.

Sie beheben diese Probleme sowohl durch die Schleife in logOutput() zu

Wechsel
pthread_mutex_lock(&logFileMutex); 
while (!stop) 
{ 
    while (!stop && bufferIsEmpty) 
     pthread_cond_wait(&emptyCond, &logFileMutex); 

    while (!bufferIsEmpty) 
    { 
     ch = buffer[out++]; 
     out %= BUFFER_SIZE; 
     if (--count == 0) 
      bufferIsEmpty = 1; 
     fputc(ch, f); 
    } 
    bufferIsFull = 0; 
    pthread_cond_signal(&fullCond); 
} 
pthread_mutex_unlock(&logFileMutex); 

und Ändern stopLog() zu:

void stopLog() { 
    pthread_mutex_lock(&logFileMutex); 
    stop = 1; 
    pthread_cond_signal(&emptyCond); 
    pthread_mutex_unlock(&logFileMutex); 
} 

Wenn nun stopLog() aufgerufen wird, wird logOutput() aufwachen, Prozess jede Protokollnachrichten, die zur gleichen Zeit wie der Stopp und der Ausgang gesendet wurden.