You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言子进程实现日志器程序阻塞无输出问题求助

C语言子进程日志器无输出问题排查

我用C语言实现了一个基于子进程的日志器,用来记录sensor_db.c中数据库文件的打开、写入、关闭操作,但运行后日志子进程一直处于等待状态,没有任何输出。调试时,子进程执行到read()函数就停住了。


相关代码

sensor_db.c

#include <stdio.h>
#include <stdbool.h>
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "logger.h"
#include <fcntl.h>
#include <sys/wait.h>
// status 1: file opening error
// status 2: fork failure
// status 3: writing to db file failure
// status 4: file failed to close
// status 5: pipe creation failure

/* definition of global vars */


FILE* open_db(char *filename, bool append) {
    FILE *fp;
    if (append == true) {
        fp = fopen(filename, "a");
    } else {
        fp = fopen(filename, "w");
    }
    create_log_process();
    // Error handling for file opening
    if (fp == NULL) {
//        create_log_process();
        write_to_log_process("ERROR: could not open db file.");
        perror("Error occurred during file opening");
        exit(1);
    }

    // Communicate with the log process
    write_to_log_process("Data file opened.");
    return fp;
}


int insert_sensor(FILE * f, sensor_id_t id, sensor_value_t value, sensor_ts_t ts) {
    if (fprintf(f, "%d, %lf, %ld \n", id, value, ts) < 0) {
        write_to_log_process("ERROR: could not write to db file.");
        perror("Error writing to file");
        fclose(f);
        exit(3);
    }

    // Communicate with the log process
    write_to_log_process("Data inserted.");
    return 0;
}

int close_db(FILE * f) {
    if ( fclose(f) == EOF) {
        write_to_log_process("ERROR: could not close db file.");
        perror("Error closing file");
        exit(4);
    };
    // Communicate with the log process
    write_to_log_process("Data file closed.");
    end_log_process();

    return 0;
}

logger.c

#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
#define BUFFER_SIZE 1000

// status 1: file opening error
// status 2: fork failure
// status 3: writing to log file failure
// status 4: file failed to close
// status 5: pipe creation failure
// status 6: writing to log file failure

/*global variables (for file opening + pipe)*/
FILE *fp;
int fd[2], pid;
int i = 0;

int create_log_process() {
    // log file opening
    fp = fopen("gateway.log", "a");
    if (fp == NULL) {
        perror("Error occurred during log file opening");
        exit(1);
    }
    // creation of communication and child process
    if (pipe(fd) == -1) {
        perror("Error occurred during pipe creation");
        exit(5);
    };
    pid = fork();
    // error handle
    if (pid == -1) {
        perror("fork failed");
        exit(2);
    } else if (pid == 0) {
        close(fd[1]); // closing write_end.
        char received_message[BUFFER_SIZE];
        size_t message_length;
        while(read(fd[0], &message_length, sizeof(size_t)) > 0) {
            if ((read(fd[0], received_message, message_length)) > 0) {
                printf("test\n");
                printf("child process reads: %s \n", received_message);
                // timestamp creation.
                time_t timer;
                time(&timer);
                struct tm *timestamp_info;
                timestamp_info = localtime(&timer);
                char timestamp[20];
                strftime(timestamp, sizeof(timestamp), "%a %b %d %X %Y", timestamp_info);

                // writing message to log file.
                if (fprintf(fp, "%d - %s - %s\n", i++, timestamp, received_message) < 0) {
                    perror("Error occurred during writing to log file");
                    fclose(fp);
                };
                printf("test\n");
            }
        }
        close(fd[0]);
        fclose(fp);
        exit(0);
    }
    return 0;
}
//
//int write_to_log_process(char *msg) {
//    if (pid > 0) {
//        char message[BUFFER_SIZE];
//        strncpy(message, msg, sizeof(message) - 1);
//        message[sizeof(message) - 1] = '\0';  // Ensure null-termination
//        if (write(fd[1], message, strlen(message) + 1) == -1) {
//            perror("Error occurred during writing to pipe");
//            exit(3);
//        }
//            // opmerking!!! sizeof(msg) don't use, = size of the pointer! use buffer_size...
//            // with buffer_size you know for sure the nbytes you want to copy at most + is configurable.
//    }
//    return 0;
//}
int write_to_log_process(char *msg) {
    size_t msg_length = strlen(msg) + 1;
    write(fd[1], &msg_length, sizeof(size_t)); // writing the length to be read.
    if (write(fd[1], msg, strlen(msg) + 1) == -1) {  // writing the message as well.
        perror("Error occurred during writing to pipe");
        exit(3);
    }
    return 0;
}
// opmerking!!! sizeof(msg) don't use, = size of the pointer! use buffer_size...
// with buffer_size you know for sure the nbytes you want to copy at most + is configurable.

int end_log_process() {
    close(fd[0]);
    close(fd[1]);
    wait(NULL);
    return 0;
}

测试代码

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <time.h>

#include <sys/types.h>

#include "sensor_db.h"
#include "logger.h"
#include "config.h"

int main()
{
    FILE *f = open_db("sensor_db.csv", true);

    sleep(1);
    sensor_id_t id = 1;
    sensor_value_t v = 0.001;
    sensor_ts_t ts = time(NULL);
    insert_sensor(f, id, v, ts);

    id = 2;
    v = 0.002;
    ts = time(NULL);
    insert_sensor(f, id, v, ts);
    id = 3;
    v = 0.003;
    ts = time(NULL);
    insert_sensor(f, id, v, ts);
    sleep(5);
    insert_sensor(f, 4, v, ts);
    close_db(f);

    return 0;
}

问题根源及修复方案

1. 父进程未关闭管道读端,导致子进程阻塞

创建管道和子进程后,父进程没有关闭管道的读端fd[0],管道读端在父进程中一直处于打开状态,子进程的while(read(fd[0], ...) > 0)循环永远不会遇到EOF,会一直阻塞等待数据。

修复:在create_log_process的父进程分支中添加关闭读端的代码:

int create_log_process() {
    // ... 现有代码 ...
    pid = fork();
    if (pid == -1) {
        perror("fork failed");
        exit(2);
    } else if (pid == 0) {
        // 子进程代码保持不变
    } else {
        // 父进程关闭管道读端
        close(fd[0]);
    }
    return 0;
}

2. write调用未处理部分写入情况

管道是字节流,write可能只写入部分数据,导致子进程读取的长度或消息不完整,进而阻塞。需要确保所有数据都写入管道。

修复:封装一个确保全部写入的函数,替换原write调用:

ssize_t full_write(int fd, const void *buf, size_t count) {
    size_t remaining = count;
    const char *p = buf;
    while (remaining > 0) {
        ssize_t n = write(fd, p, remaining);
        if (n == -1) {
            if (errno == EINTR) continue; // 被信号中断,重试
            return -1;
        }
        remaining -= n;
        p += n;
    }
    return count;
}

// 修改write_to_log_process
int write_to_log_process(char *msg) {
    size_t msg_length = strlen(msg) + 1;
    if (full_write(fd[1], &msg_length, sizeof(size_t)) == -1) {
        perror("Error writing length to pipe");
        exit(3);
    }
    if (full_write(fd[1], msg, msg_length) == -1) {
        perror("Error writing message to pipe");
        exit(3);
    }
    return 0;
}

3. 日志文件缓冲区未手动刷新

日志文件fp默认是行缓冲模式,子进程写入日志后如果不手动刷新,缓冲区数据可能不会立即写入文件,导致看起来没有输出。

修复:在fprintf后添加缓冲区刷新操作:

if (fprintf(fp, "%d - %s - %s\n", i++, timestamp, received_message) < 0) {
    perror("Error occurred during writing to log file");
    fclose(fp);
    exit(6);
};
fflush(fp); // 手动刷新缓冲区

内容的提问来源于stack exchange,提问作者dsdfs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:37:31