c语言中的周期回调
我是一个通过“ALSAAPI”编写声音播放代码的新手 我必须在一秒内反复调用函数c语言中的周期回调,c,linux,timer,callback,C,Linux,Timer,Callback,我是一个通过“ALSAAPI”编写声音播放代码的新手 我必须在一秒内反复调用函数send_output()10次,如下所示: while(true) { send_output(); usleep(100000); } 但这是一种糟糕的编程方式,因为在usleep()函数中,处理器仍然忙于执行代码 我想知道如何(因为我知道它存在)将函数send\u output()放入定期回调函数中,以便在调用之间,处理器可以自由地执行其他繁重的任务。你能帮我吗 另外,我正在“Beagle
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:不,我想暂停。。我的错误是没有提前查看睡眠手册如果你想被暂停,那么问题是什么?我想你已经对了。