[置顶] Pandas的DataFrame

摘要: 1. 手工创建DataFrame 1 a = [[1, 2, 2],[3,None,6],[3, 7, None],[5,None,7]] 2 data = DataFrame(a) 2. Excel数据数据没有顶头的处理 1 import os 2 import pandas as pd 3 ba 阅读全文

posted @ 2019-08-30 13:12 张叫兽的技术研究院 阅读(420) 评论(0) 推荐(0) 编辑

[置顶] windows的github教程

摘要: 未曾提交的本地仓库,push到远程仓库报错: 本地仓库push到远程仓库报错: error: src refspec master does not match anyerror: failed to push some refs to 'https://gitee.com/lorryZhang/m 阅读全文

posted @ 2019-04-05 14:51 张叫兽的技术研究院 阅读(500) 评论(0) 推荐(0) 编辑

[置顶] 好文章

摘要: 概率图 https://www.coursera.org/learn/probabilistic-graphical-models https://blog.csdn.net/u014380165/article/list/5 AI之路,作者写了很多视觉相关算法心得文章 http://openacc 阅读全文

posted @ 2018-10-06 17:03 张叫兽的技术研究院 阅读(447) 评论(0) 推荐(0) 编辑

2025年1月18日

settimer的坑

现象说明

某监控程序,想要实现间隔3秒做一些事情,间隔1分钟做一些事情,但是实测的时候发现只有最后一个定时器有执行。

代码如下,代码层面上还做了些许重构,将定时器部分进行封装,本意是方便添加定时任务:

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

// 定时器触发时调用的信号处理函数
void timer_handler_world(int sig)
{
    // 打印 "Hello, World"
    printf("Hello, World\n");
}

void timer_handler_c(int sig)
{
    // 打印 "Hello, World"
    printf("Hello, C language\n");
}

void set_timer(timer_t timer_id, int first_timespan_sec, int time_span_sec, __sighandler_t action)
{
    struct sigaction sa;
    struct itimerspec timer_spec;
    // timer_t timer_id;

    // 设置信号处理函数
    sa.sa_handler = action;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);

    // 注册 SIGALRM 信号
    if (sigaction(SIGALRM, &sa, NULL) == -1)
    {
        perror("sigaction");
        return;
    }

    // 创建定时器
    if (timer_create(CLOCK_REALTIME, NULL, &timer_id) == -1)
    {
        perror("timer_create");
        return;
    }
    printf("timer id: %p\n", timer_id);

    // 设置定时器
    timer_spec.it_value.tv_sec = first_timespan_sec; // 初始延迟 3 秒
    timer_spec.it_value.tv_nsec = 0;
    timer_spec.it_interval.tv_sec = time_span_sec; // 每隔 3 秒触发一次
    timer_spec.it_interval.tv_nsec = 0;

    if (timer_settime(timer_id, 0, &timer_spec, NULL) == -1)
    {
        perror("timer_settime");
        return;
    }
}

int main()
{
    timer_t timer_id_1;
    timer_t timer_id_2;

    set_timer(timer_id_1, 3, 3, timer_handler_world);
    set_timer(timer_id_2, 5, 5, timer_handler_c);
    // 程序将持续运行,直到手动终止
    while (1)
    {
        // 等待定时器信号的到来
        pause();
    }

    return 0;
}

原因分析

使用set_timer的触发是通过内核的信号触发的,信号的响应,是进程级别的动作;对于一个信号的响应,只能绑定一个函数;而本次实现,则是使用一个信号SIGALRM,尝试多次绑定函数,内核在处理信号绑定处理函数,在设计上就是后面绑定函数直接覆盖前面的。

所以,这个问题并不是timer_settime机制问题,而是信号机制使用不当问题。

解决方案

  • 方案一:如果是定时事件之间事件间隔是整数倍关系,则通过添加计数器完成,比如两个计时计时任务,一个1分钟,一个三分钟,那么设置一个1分钟的定时器,每次触发1分钟的任务每次都执行,三分钟的通过分析计数器,只有计数器达到了3次,才会执行,执行完毕后记得计数器清零

  • 方案二:方案一的问题就是扩展性不足,只能满足整数倍的场景;如果不是整数倍关系,那么搞一个最小公约数,比如一个是2分钟,一个是3分钟,那么可以搞一个1分钟的定时器,再维持2个计数器:2分钟计数器和3分钟计数器,每次timer触发,计数器+1,2分钟计数器满足计数达到2则触发,3分钟计数器则是计数达到3则触发

  • 方案三:方案二其实扩展性也是不足的,如果后面再来一个需要半分钟触发的需求怎么办?扩展性最好的方案还是启动一个线程,然后通过让线程休眠指定时长的方式,完成定时任务;但是sleep的方式有一个问题就是时间不准确,因为一个进程sleep的时候,意味着cpu资源已经交出去了,即使计时时间到了,还是需要以来内核进行调度,才能够被唤醒;所以无法保证精确的时延。

扩展

timer_settime注册的定时器,默认是触发SIG_ALARM,如果想要自定义触发信号,可以参考一下实现;核心差别就是在于函数timer_create的第二个参数,上述默认采用SIGALARM信号通知,第二个参数是NULL,而如果想要自定义通知信号,需要为第二个参数,构建一个sigevent结构体,并将自定义的信号赋值给sigevent的sigev_signo成员,然后传入timer_create函数中:

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

// 定时器触发时调用的信号处理函数
void timer_handler_world(int sig){...}

void timer_handler_c(int sig){...}

// 设置定时器函数
void set_timer(timer_t *timer_id, int first_timespan_sec, int time_span_sec, __sighandler_t action, int signal)
{
    struct sigaction sa;
    struct itimerspec timer_spec;
    struct sigevent sev;

    // 设置信号处理函数
    sa.sa_handler = action;
    sa.sa_flags = SA_RESTART; // 确保信号处理后系统调用能继续
    sigemptyset(&sa.sa_mask);

    // 注册信号处理
    if (sigaction(signal, &sa, NULL) == -1)
    {
        perror("sigaction");
        return;
    }
    else
    {
        printf("sigaction create successful!\n");
    }

    sev.sigev_notify = SIGEV_SIGNAL; // 使用信号通知
    sev.sigev_signo = SIGUSR1;       // 自定义触发信号为 SIGUSR1
    // 创建定时器
    if (timer_create(CLOCK_REALTIME, &sev, timer_id) == -1)
    {
        perror("timer_create");
        return;
    }
    printf("timer id: %p\n", *timer_id);

    // 设置定时器
    ... ...
}

int main()
{
    timer_t timer_id_1;
    timer_t timer_id_2;

    // 设置定时器1,使用 SIGUSR1 信号触发
    set_timer(&timer_id_1, 3, 3, timer_handler_world, SIGUSR1);

    // 设置定时器2,使用 SIGUSR2 信号触发
    set_timer(&timer_id_2, 5, 5, timer_handler_c, SIGUSR2);

    // 程序将持续运行,直到手动终止
    while (1)
    {
        // 等待信号
        pause();
        printf("receive signal!\n");
    }

    return 0;
}

posted @ 2025-01-18 16:27 张叫兽的技术研究院 阅读(7) 评论(0) 推荐(0) 编辑

2024年11月24日

Git旧文件覆盖引发思考

摘要: 一天,我的同事过来找到我,和我讲:张叫兽,大事不好,我的文件被人覆盖了。git是真的不好用啊 git不好用?文件被覆盖;瞬间我似乎知道了什么,让我想到了某位男明星的语法:他一定是犯了全天下git初学者都会犯的错误。 一了解,果不其然 先说结论:git拉取,如果发生冲突,尽量保证Stage空间文件都提 阅读全文

posted @ 2024-11-24 13:54 张叫兽的技术研究院 阅读(4) 评论(0) 推荐(0) 编辑

2022年1月4日

STM32(3):番外篇之Let's GO!

摘要: Let's GO! 能够看到这里的盆友,相信前面两个章节并没有劝退,我觉得前面两个章节可能是难度最大的两篇了,如果能够搞掂,后面的内容其实反而简单。但是前面两个章节是嵌入式开发"生存必要的技能"(理解寄存器以及查看手册),否则后面也是寸步难行。 Go! Go! Go! 让我们继续探索STM32的世界 阅读全文

posted @ 2022-01-04 20:16 张叫兽的技术研究院 阅读(201) 评论(0) 推荐(0) 编辑

2022年1月3日

STM32(2):点亮LED(下)

摘要: 本文摘自: https://blog.csdn.net/xiashiwendao/article/details/122292404 概述 点亮LED表面看起来貌似很简单,但是如何想要搞清楚其背后牵涉的每一行代码的具体含义,还是需要花费一些功夫的,而且,只有把LED的背后只是搞清楚了,才算嵌入式开发 阅读全文

posted @ 2022-01-03 21:46 张叫兽的技术研究院 阅读(320) 评论(0) 推荐(0) 编辑

STM32(1):点亮LED(上)

摘要: 本文摘自: https://blog.csdn.net/xiashiwendao/article/details/122291583 概述 今天我们的开启了STM32开发的第一站:点亮LED,今天的内容包含了很多基础的知识,也有一些劝退的意味,不过,如果你能够扛得住这波攻势的,我觉得你高嵌入式方面真 阅读全文

posted @ 2022-01-03 19:52 张叫兽的技术研究院 阅读(1027) 评论(0) 推荐(0) 编辑

2021年4月22日

nodepad++查看2进制/ 16进制文件

摘要: 在Plugins里面点击Plugin Admin... 搜索HEX,就可以看到HEX-editor,然后安装; 完成后,打开二进制文件,乱码,然后Plugins→HEX-Editor→View HEX,即可实现查看16进制或者二进制; 想要进行2进制和16进制的切换,在展示域右键→View In,选 阅读全文

posted @ 2021-04-22 11:31 张叫兽的技术研究院 阅读(467) 评论(0) 推荐(0) 编辑

2021年3月13日

windows下关闭设备中断连接的声音

摘要: windows下面设备中断(断开连接),重新连接上会有声音,比较烦;关闭方法: 桌面右键->个性化->主题->声音 然后在弹出的框中“声音”tab里面的windows下面的设备中断,设备连接的声音设置为“无”即可。 点击确认,这样就再没有咚咚的声音了。 阅读全文

posted @ 2021-03-13 06:19 张叫兽的技术研究院 阅读(891) 评论(0) 推荐(0) 编辑

2021年3月6日

Linux的缩写

摘要: 命令缩写: ls:list(列出目录内容) cd:Change Directory(改变目录)su:switch user 切换用户rpm:redhat package manager 红帽子打包管理器pwd:print work directory 打印当前目录 显示出当前工作目录的绝对路径ps: 阅读全文

posted @ 2021-03-06 17:03 张叫兽的技术研究院 阅读(219) 评论(0) 推荐(0) 编辑

2020年12月24日

Beyond Compare的revoke问题解决

摘要: windows: 直接删除: C:\Users\%User_name%\AppData\Roaming\Scooter Software\Beyond Compare 4 Linux(有待验证): 1.删除下面目录中的所有文件: /home/xxx/.config/bcompare 2.重新破解 $ 阅读全文

posted @ 2020-12-24 07:06 张叫兽的技术研究院 阅读(690) 评论(0) 推荐(0) 编辑

2020年6月23日

Apriori算法

摘要: 算法原理 如果某个项集是频繁集,那么这个频繁集中任意子集都是频繁集。所谓频繁集即指该组合出现的概率达到了指定水平; Aprior算法用来实现查找K个最大频繁项,什么是最大频繁项,就是一组频繁项,任T个子项组合都是T项组合中最频繁的; 频繁项的评估标准有三个,分别是: 支持度(Support),代表含 阅读全文

posted @ 2020-06-23 17:19 张叫兽的技术研究院 阅读(654) 评论(0) 推荐(0) 编辑

导航

< 2025年2月 >
26 27 28 29 30 31 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 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示