c语言中的周期回调

c语言中的周期回调,c,linux,timer,callback,C,Linux,Timer,Callback,我是一个通过“ALSAAPI”编写声音播放代码的新手 我必须在一秒内反复调用函数send_output()10次,如下所示: while(true) { send_output(); usleep(100000); } 但这是一种糟糕的编程方式,因为在usleep()函数中,处理器仍然忙于执行代码 我想知道如何(因为我知道它存在)将函数send\u output()放入定期回调函数中,以便在调用之间,处理器可以自由地执行其他繁重的任务。你能帮我吗 另外,我正在“Beagle

我是一个通过“ALSAAPI”编写声音播放代码的新手

我必须在一秒内反复调用函数
send_output()
10次,如下所示:

while(true)
{
     send_output();
     usleep(100000);
}
但这是一种糟糕的编程方式,因为在
usleep()函数中,处理器仍然忙于执行代码

我想知道如何(因为我知道它存在)将函数
send\u output()
放入定期回调函数中,以便在调用之间,处理器可以自由地执行其他繁重的任务。你能帮我吗

另外,我正在“Beagleboard”上编程,它的时钟频率非常低,还需要执行其他任务


谢谢。

manusleep

   usleep - suspend execution for microsecond intervals

您必须在
多线程的框架中执行此操作

根据您的标签,假设您正在Linux上编程,因此:

void thread_funtion()
{
    while(true)
    {
         send_output();
         usleep(100000);
    }
}
通过以下方式在主线程中调用此函数:

pthread_t pid;
pthread_create(&pid, NULL, thread_function, NULL);
请注意:

  • #包括
  • 如果您使用
    gcc
    命令遇到错误,请尝试
    gcc-pthread
    命令

  • 很简单,您应该避免使用那样的同步。改用事件系统实现。定义一个接口并将其注册到类作为侦听器。每次你们的班级执行一些动作时,你们都会收到事件通知。您可以了解Java侦听器实现,也可以了解(桥接、策略、观察者)设计模式。C++中的接口实现将类似于:

    class IActionListener
    {
    public:
     virtual void actionPerformed( ... some arguments ... )=0;
    };
    
    执行此操作,如:

    class ConcreteActionListener: public IActionListener
    {
    public:
     void actionPerformed( ... some arguments ... )
     {
       // do your staff here.
     }
    };
    
    选中此项:
    应用程序中需要协调多个事项的典型主循环以
    select
    函数为中心,该函数等待一组文件描述符上的事件或超时

    然后,您的ALSA循环变为

    // This will keep the time when ALSA expects the next packet
    struct timeval alsa_timeout;
    
    // Initialize timeout with current time
    gettimeofday(&alsa_timeout, 0);
    
    for(;;) {
        // Get current time
        struct timeval now;
        gettimeofday(&now, 0);
    
        // Whether to re-check the current time before going to sleep
        bool restart = false;
    
        if(now.tv_sec > alsa_timeout.tv_sec ||
                (now.tv_sec == alsa_timeout.tv_sec && now.tv_usec >= alsa_timeout.tv_usec)) {
            send_output();
            alsa_timeout.tv_usec += 100000;
            if(alsa_timeout.tv_usec > 1000000) {
                alsa_timeout.tv_sec += alsa_timeout.tv_usec / 1000000;
                alsa_timeout.tv_usec %= 1000000;
            }
            restart = true;
        }
    
        // If we performed some action, this would have taken time, so we need
        // to re-fetch the current time
        if(restart)
            continue;
    
        // Determine when the next action is due
        struct timeval next_timeout;
    
        // We only have one action at the moment, which is ALSA. Otherwise, this is the place
        // where you look for the earliest time you need to wake up.
        next_timeout.tv_sec = alsa_timeout.tv_sec;
        next_timeout.tv_usec = alsa_timeout.tv_usec;
    
        struct timeval relative_time;
        if(next_timeout.tv_usec >= now.tv_usec) {
            relative_time.tv_usec = next_timeout.tv_usec - now.tv_usec;
            relative_time.tv_sec = next_timeout.tv_sec - now.tv_sec;
        } else {
            relative_time.tv_usec = 1000000 - now.tv_usec + next_timeout.tv_usec;
            relative_time.tv_sec = next_timeout.tv_sec + 1 - now.tv_usec;
        }
    
        // Other parameters become important when you do other work
        int rc = select(0, 0, 0, 0, &relative_time);
    
        if(rc == 0)
            continue;
        if(rc == -1)
            break;
    
        // Handle file descriptor based work here
    }
    
    请注意,我在计算中使用了绝对时间,并为我发送的每个样本包增加了绝对时间——无论ALSA子系统将数据传输到声卡需要多长时间,以及当我错过超时时间时(因为某些其他功能需要超过100毫秒才能完成),这都会保持数据速率不变将调用输出函数两次,以重新填充ALSA缓冲区

    您可能需要添加一些额外的代码:

    • 如果发生缓冲区不足,请通过将alsa_超时值重置为当前时间来重新启动,这样我们就不会丢失同步
    • 如果流运行很长时间,您可能需要稍微调整超时,因为声音芯片DAC时钟未与
      gettimeofday()后面的系统时钟同步。
    • 如果调整了系统时钟,则需要重新同步循环(您可以忽略夏令时,
      gettimeofday()
      返回UTC,但如果您运行NTP客户端或允许在某处设置日期和时间,则需要处理该问题)

    usleep
    不是一个繁忙的循环,它会挂起调用线程(或进程)。哎呀!很抱歉我没注意到。我还可以举一个周期性回调函数的例子吗?@higherDefender:你的例子完全符合你的要求。如果您不提供更多信息,我们将无法帮助您。您知道定期回调函数吗?正确!但我不认为他的问题是“为什么暂停”。他的问题是“如何避免被暂停”。@Skyler:不,我想暂停。。我的错误是没有提前查看睡眠手册如果你想被暂停,那么问题是什么?我想你已经对了。