Linux系统编程之时序竞态

pause函数

在这里插入图片描述
在这里插入图片描述

/*
 *  @file           mysleep.c
 *  @brief          使用pause和alarm函数来实现sleep函数
 *  @version 1.1    无
 *  @author         北豼
 *  @date           2022年5月11日
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>

/*
 * 函数名称:    catch_sigalrm
 * 函数介绍:    捕捉到信号后调用的函数
 * 输入参数:    int signo
 * 输出参数:    无
 * 返回值  :    无
 */

void catch_sigalrm(int signo)
{
        ;
}

/*
* 函数名称:    mysleep
* 函数介绍:    使用pause和alarm函数来实现sleep函数
* 输入参数:    unsigned int seconds
* 输出参数:    无
* 返回值  :    int ret
*/

unsigned int mysleep(unsigned int seconds)
{
        int ret;
        struct sigaction act;
        struct sigaction oldact;

        //设置捕捉函数结构体的值
        act.sa_handler = catch_sigalrm;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;

        //注册捕捉函数
        ret = sigaction(SIGALRM, &act, &oldact);
        if (ret == -1)
        {
                perror("sigaction error");
                exit(1);
        }

        //设置定时时间
        alarm(seconds);

        //阻塞等待捕捉到信号
        ret = pause();
        if (ret == -1 && errno == EINTR)
        {
                printf("pause sucess\n");
        }

        ret = alarm(0);
        sigaction(SIGALRM, &oldact, NULL);              //恢复SIGALRM默认的值

        return ret;
}

int main(void)
{
        while (1)
        {
                mysleep(3);
                printf("-----------------\n");
        }

        return 0;
}

每3秒打印输出一次
在这里插入图片描述

时序竟态

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

/*
 *  @file           sigsuspend.c
 *  @brief          使用sigsuspend和alarm函数来实现sleep函数
 *  @version 1.1    无
 *  @author         北豼
 *  @date           2022年5月11日
 */

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

/*
 * 函数名称:    sig_alrm
 * 函数介绍:    捕捉到信号后调用的函数
 * 输入参数:    int signo
 * 输出参数:    无
 * 返回值  :    无
 */

void sig_alrm(int signo)
{

}

/*
 * 函数名称:    mysleep
 * 函数介绍:    使用sigsuspend和alarm函数来实现sleep函数
 * 输入参数:    unsigned int nsecs
 * 输出参数:    无
 * 返回值  :    unsigned int unslept
 */

unsigned int mysleep(unsigned int nsecs)
{
        struct sigaction newact;
        struct sigaction oldact;
        sigset_t newmask;
        sigset_t oldmask;
        sigset_t suspmask;
        unsigned int unslept;

        //1.为SIGALRM设置捕捉函数,一个空函数
        newact.sa_handler = sig_alrm;
        sigemptyset(&newact.sa_mask);
        newact.sa_flags = 0;
        sigaction(SIGALRM, &newact, &oldact);

        //2.设置阻塞信号集,阻塞SIGALRM信号
        sigemptyset(&newmask);
        sigaddset(&newmask, SIGALRM);
        sigprocmask(SIG_BLOCK, &newmask, &oldmask);

        //3.定时n秒,到时间后可以产生SIGALRM信号
        alarm(nsecs);

        /*
         *4.构造一个调用sigsuspend临时有效的阻塞信号集,
         *在临时阻塞信号集里解除SIGALRM的阻塞
         */
        suspmask = oldmask;
        sigdelset(&suspmask, SIGALRM);

        /*
         *5.sigsuspend调用期间,采用临时阻塞信号集suspmask替换原有阻塞信号集
         *这个信号集中不包含SIGALRM信号,同时挂起等待,
         *当sigsuspend被信号唤醒返回时,恢复原有的阻塞信号集
         */
        sigsuspend(&suspmask);
        unslept = alarm(0);

        //6.恢复SIGALRM原有的处理动作,呼应前面注释1
        sigaction(SIGALRM, &oldact, NULL);

        //7.解除对SIGALRM的阻塞,呼应前面注释2
        sigprocmask(SIG_SETMASK, &oldmask, NULL);

        return unslept;
}

int main(void)
{
        while (1)
        {
                mysleep(3);
                printf("-----------------\n");
        }

        return 0;
}

在这里插入图片描述
在这里插入图片描述

全局变量的异步IO

/*
 *  @file           sync_process.c
 *  @brief          通过全局变量实现父子进程之间交替数数
 *  @version 1.1    无
 *  @author         北豼
 *  @date           2022年5月11日
 */

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

int n = 0;
int flag = 0;

void sys_err(char *str)
{
        perror(str);
        exit(1);
}

//子进程的信号处理函数
void do_sig_child(int num)
{
        printf("I am child %d \t %d\n", getpid(), n);
        n += 2;
        flag = 1;
        sleep(1);
}

//父进程的信号处理函数
void do_sig_parent(int num)
{
        printf("I am parent %d \t %d\n", getpid(), n);
        n += 2;
        flag = 1;
        sleep(1);
}

int main(void)
{
        pid_t pid;
        struct sigaction act;

        if ((pid = fork()) < 0)
        {
                sys_err("fork");
        }
        else if (pid > 0)               //父进程
        {
                n = 1;
                sleep(1);

                //注册SIGUSR2信号捕捉函数
                act.sa_handler = do_sig_parent;
                sigemptyset(&act.sa_mask);
                act.sa_flags = 0;
                sigaction(SIGUSR2, &act, NULL);

                do_sig_parent(0);

                while (1)
                {
                        if (flag == 1)
                        {
                                kill(pid, SIGUSR1);
                                flag = 0;
                        }
                }
        }
        else if (pid == 0)              //子进程
        {
                n = 2;

                //注册SIGUSR1信号捕捉函数
                act.sa_handler = do_sig_child;
                sigemptyset(&act.sa_mask);
                act.sa_flags = 0;
                sigaction(SIGUSR1, &act, NULL);

                while (1)
                {
                        if (flag == 1)
                        {
                                kill(getppid(), SIGUSR2);
                                flag = 0;
                        }
                }
        }
}

在这里插入图片描述
如果把父子进程的sleep(1);去掉就会出现和上面一样的时序竞态的问题,导致程序异常,我们可以不用全局变量直接传信号过去就行了,或者用全局变量的时候要用锁

可重入函数、不可重入函数

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是北豼不太皮吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值