3

我正在用 C 语言编写一个“简单”的点唱机,它可以在 Raspberry Pi 上运行,但我很难弄清楚优化其性能的最佳方法是什么。

它的设置方式是我有一个处理所有图形(通过ncurses)和数据处理的进程,另一个我将命令发送到一个mp3播放应用程序(xmms2),然后我用两个管道将两者连接起来形成一个简单的桥,发送诸如“获取当前播放列表位置”之类的消息并以“当前播放列表位置:0”作为响应(尽管没有那么冗长)。

所有管道都设置为非阻塞,但在发送这些命令时我仍然遇到很多延迟。

意识到这可能是一个抽象的问题,但我对 C 语言不是非常精通,并且会感谢任何类型的输入,无论我是否走错了方向,或者没有如何设置.

提前致谢!

主循环:

init_xmms_bridge();

pid_t pid = fork();

while(true == true)
{
    update_xmms_bridge(pid);
    if(pid != 0)
        update_screen();
}

图形.c

void update_screen(void)
{
    /* update playlist if that has changed, 
    library display if keys has been pressed etc */

    usleep(50000); // Wait .05 seconds
    refresh(); // Refresh ncurses screen
}

xmms_bridge.c(部分)

void init_xmms_bridge(void)
{
    pipe(xmms_pipe_in);
    pipe(xmms_pipe_out);

    // Set all pipes as non-blocking
    int flags = fcntl(xmms_pipe_in[0], F_GETFL, 0);
    fcntl(xmms_pipe_in[0], F_SETFL, flags | O_NONBLOCK);

    flags = fcntl(xmms_pipe_in[1], F_GETFL, 0);
    fcntl(xmms_pipe_in[1], F_SETFL, flags | O_NONBLOCK);

    flags = fcntl(xmms_pipe_out[0], F_GETFL, 0);
    fcntl(xmms_pipe_out[0], F_SETFL, flags | O_NONBLOCK);

    flags = fcntl(xmms_pipe_out[1], F_GETFL, 0);
    fcntl(xmms_pipe_out[1], F_SETFL, flags | O_NONBLOCK);

}

// Receive data from pipes
void update_xmms_bridge(pid_t process_id)
{
    if(process_id == 0) // Child process
    {
        close(xmms_pipe_out[1]);
        bytes_read_out = read(xmms_pipe_out[0],xmms_pipe_buffer_out,sizeof(xmms_pipe_buffer_out));

        if(bytes_read_out != -1)
            xmms_receive_call(xmms_pipe_buffer_out,XMMSDirectionOut);
    }
    else
    {
        close(xmms_pipe_in[1]);
        bytes_read_in = read(xmms_pipe_in[0],xmms_pipe_buffer_in,sizeof(xmms_pipe_buffer_in));

        if(bytes_read_in != -1)
            xmms_receive_call(xmms_pipe_buffer_in,XMMSDirectionIn);
    }
}

// Send data to pipes
void bridge_call(int pipe[2],const char command,char *parameters)
{
    // Make sure it works even if parameters is null
    char call[parameters == NULL ? 3 : strlen(parameters)+3];

    /* Add separator to deal with the fact
    that multiple calls can be made before 
    the loop reads the pipe. */
    call[0] = SEPARATOR_CHARACTER;
    call[1] = command;
    call[2] = '\0';

    // Concentate string before sending through pipe
    if(parameters != NULL)
        strcat(call,parameters);

    close(pipe[0]);
    write(pipe[1],call,strlen(call));
}

void xmms_bridge_call(const char command,char *parameters)
{
    bridge_call(xmms_pipe_out,command,parameters);
}

void jukebox_bridge_call(const char command,char *parameters)
{
    bridge_call(xmms_pipe_in,command,parameters);
}
4

1 回答 1

0

在阅读了用户 Kenneth 指出的内容后,我通过用线程替换进程分叉解决了这个问题。由于我的大多数调用都应该是一种方式,所以我的典型线程代码如下所示:

pthread_t thread;
pthread_attr_t thread_attr;
int thread_error;

thread_error = pthread_attr_init(&thread);

if(thread_error)
{
    /* Handle error */
    return;
}

/* Make thread detached so I don't need to worry about it after it's creation */
result = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);

if(!thread_error)
{
    thread_error = pthread_create(&thread,&thread_attr,<xmms-calling-funtion>,<arguments>);

    pthread_attr_destroy(&thread_attr);

    if(thread_error)
        /* Handle error */
}
else
    /* Handle error */

正如用户 Craig 所提到的,有一个 xmms2 C 客户端库,但我从未设法将它链接到我的程序,尽管我确信使用它会更好。我仍然觉得这个答案更多地与我的问题有关,这更多是关于 Raspberry Pi 上的性能而不是 xmms2。

如果有人确实在 Raspberry Pi 上构建了一个项目并成功地将其链接到 xmms2 C 客户端库,我很想听听你是如何做到的!

链接到客户端库教程存储库:

git://git.xmms2.org/xmms2/xmms2-tutorial.git

对于好奇的人,这就是用户界面最终的样子:

基于树莓派的点唱机运行 ncurses 的图片

于 2013-08-21T09:45:54.533 回答