我是一名新手,通过“alsa api”为声音播放编写代码。
我必须在一秒钟内重复调用函数send_output()
10次:
while(true)
{
send_output();
usleep(100000);
}
但这是一种糟糕的编程方式,因为在usleep()
函数处理器中仍然忙于执行代码。
我想知道将函数send_output()
放入周期性回调函数的方式(因为我知道它存在),以便在调用之间,处理器可以保持空闲以执行其他繁重的任务。你能救我吗?
P.S。我正在使用'Beagleboard'进行编程,它的时钟频率非常低,并且还需要执行其他任务。
感谢。
答案 0 :(得分:1)
man usleep
usleep - suspend execution for microsecond intervals
答案 1 :(得分:1)
您必须在multi-threads
。
根据你的标签,假设你是在Linux上编程,所以:
void thread_funtion()
{
while(true)
{
send_output();
usleep(100000);
}
}
通过以下方式在主线程中调用此函数:
pthread_t pid;
pthread_create(&pid, NULL, thread_function, NULL);
请注意:
#include <pthread.h>
gcc
命令错误,请尝试gcc -pthread
命令。答案 2 :(得分:0)
很简单,你应该避免使用这样的同步。而是使用事件系统实现。定义一个接口并将其作为监听器注册到您的类。每当您的课程执行某些操作时,您将收到事件通知。您可以看一下Java监听器的实现,还可以阅读(Bridge,Strategy,Observer)设计模式。 c ++中的接口实现如下:
class IActionListener
{
public:
virtual void actionPerformed( ... some arguments ... )=0;
};
实现这样的交互式界面:
class ConcreteActionListener: public IActionListener
{
public:
void actionPerformed( ... some arguments ... )
{
// do your staff here.
}
};
答案 3 :(得分:0)
应用程序中需要协调多个事物的典型主循环以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缓冲区。
您可能需要添加一些额外的代码:
gettimeofday()
后面的系统时钟同步gettimeofday()
返回UTC,但如果您运行NTP客户端或允许在某处设置日期和时间,则需要待处理)。