c - 日志线程的奇怪行为

标签 c multithreading pthreads

我创建了以下程序来创建日志记录线程并允许其他线程写入由该线程管理的共享缓冲区。但奇怪的是,如果我没有在 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/

相关文章:

php - apache php > 用户请求

python - 使用 subprocess 模块会释放 python GIL 吗?

c - 将 pthread 变量保留在本地

c - pthread/uthread类型变量

c - 微 Controller 计数器溢出和计数

c++ - 在文件中找到字符串后替换它旁边的字符

c - C 中的 fscanf - 逗号、换行符和 %*c

c - 局部变量未初始化,找不到错误

linux - 如何跨CPU核心监控同一进程ID的所有线程?

c++ - 成员变量的更新值未反射(reflect)在 pthread 的线程路由函数中