我创建了以下程序来创建日志记录线程并允许其他线程写入由该线程管理的共享缓冲区。但奇怪的是,如果我没有在 stopLog
函数中包含对日志的写入,则日志永远不会关闭,线程也不会终止。
#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;
}
最佳答案
如果缓冲区为空且 logOutput()
被 pthread_cond_wait()
阻塞,则设置 stop = 1
不会将其唤醒向上。直到下次唤醒时它才会注意到,并写入一些日志输出即可完成此操作。
作为线程之间共享的变量,stop
也需要防止非同步访问。
您可以通过将 logOutput()
中的循环更改为
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);
并将 stopLog()
更改为:
void stopLog() {
pthread_mutex_lock(&logFileMutex);
stop = 1;
pthread_cond_signal(&emptyCond);
pthread_mutex_unlock(&logFileMutex);
}
现在,当调用 stopLog()
时,logOutput()
将唤醒,处理在停止和退出时同时发送的任何日志消息。
关于c - 日志线程的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36122192/