• 记录fork子进程执行execl阻塞卡死的问题


    源代码:

    static void *cmd_exec_thread_handler(void *arg)
    {
        pthread_cleanup_push(thread_exit_handler, arg);
    
        cmd_base_t *cmd_base = (cmd_base_t *)arg;
    
        printf("fork process\n");
        fflush(stdout);
        pid_t pid = fork();
        if (pid < 0) {
            perror("fork process error");
            printf("for process error");
            fflush(stdout);
        }
        else if (pid == 0) {
            printf("for clild process ok");
            fflush(stdout);
            cmd_base->pid = getpid();
    //        log_debug("----------> start process(pid: %d)\n", cmd_base->pid);
            execlp("bash", "bash", "-c", cmd_base->cmd, NULL);
        }
        else if (pid > 0) {
            cmd_base->pid = pid;
            int status = 0;
            log_info("------------> wait pid (%d)\n", cmd_base->pid);
            waitpid(cmd_base->pid, &status, WUNTRACED); // 等待进程结束
            if (WIFEXITED(status)) {
                log_debug("waitpid process exit OK\n");
            }
            else if (WEXITSTATUS(status)) {
                log_debug("waitpid process exit: %d\n", WEXITSTATUS(status));
            }
            else if (WIFSIGNALED(status)) {
                log_debug("waitpid process exit by signal(%s) of process(pid: %d)\n", sys_siglist[(WTERMSIG(status))], getpid());
            }
            else if (WCOREDUMP(status)) {
                log_debug("waitpid process exit by coredump error\n");
            }
        }
    
        log_debug("----------> cmd: %s is over (pid: %d)\n", cmd_base->cmd, cmd_base->pid);
        cmd_base->pid = -1;
        cmd_base->run = false;
    
        pthread_cleanup_pop(1);
        return NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    上面的函数是一个线程执行函数,调用这个函数,execlp有概率会出现阻塞的情况。
    网上翻了一下资料参考链接,造成这个的原因是产生了死锁。

    因为我使用了自己的日志库,日志库里面有互斥锁用来保证输入数据的一致性。

    在这里插入图片描述
    当父进程中的线程有调用日志打印函数时,会对互斥锁上锁,在还未解锁的情况,如果这时刚好fork子进程成功,并在子进程中执行日志打印函数的话,这个时候就会发生上面的所说的情况。

    解决方法

    • 方法一: 使用vfork代替fork。子进程不从父进程中继承锁。(此时,没有再出现过问题。但是不推荐使用vfork)
    • 方法二:自己除了调用exec外,不要再干其它事情,比如输出日志。尽量不要有关于锁的操作。
  • 相关阅读:
    计算机网络 HTTPS
    简单排序算法、二分法以及对数器
    【Java后台】从零开始的Java后台开发(一)
    在 Spring Boot2.7.1 中如何使用 Swagger3 指南
    【2023保研】双非上岸东南网安
    杭州和智高薪招聘云计算/存储/网络工程师!
    深度解读ChatGPT基本原理
    终极篇章_springMVC_文件上传和下载
    【数据分享】《中国法律年鉴》1987-2022
    【FreeRTOS】【STM32】06 FreeRTOS的使用-动态创建单任务
  • 原文地址:https://blog.csdn.net/duapple/article/details/126918593