我需要实现一种方法来睡眠这个线程,直到它有工作要做

时间:2012-06-29 14:26:22

标签: c linux multithreading pthreads embedded-linux

好吧,所以这个问题并不完全是关于线程管理......好吧,等等。我正在寻找这种配置的不同解决方案。我有一些想法,但我正在寻找可以解决问题的任何解决方案。并将权衡利弊,以实现最好的。

情况就是这样。

我有一个将生成线程的经理应用程序。该线程将持续运行并处理通过USB连接到系统的板的串行通信。管理器应用程序促进系统上运行的其他应用程序与此线程之间的通信。线程需要真正执行两件事:

  1. 通过可变定时器上的串行轮询电路板获取样品数据..通常大约每分钟一次(串行总线相当慢,波特率为4800.我无法控制)
  2. 促进与经理应用程序的通信。 (即其他应用程序将请求样本数据,管理器将请求转发给线程。线程执行操作并返回数据)
  3. 我最初的设计很简单,很有效。我使用队列和互斥体来管理经线。所以线程的逻辑如下:

    1. 初始化
    2. 虽然我们没有收到来自经理的关机命令
    3. 如果我们的计时器已启动,请轮询电路板以获取数据
    4. 否则,请检查管理员是否在队列中发布了消息。如果是的话,处理它
    5. 问题是我没有考虑CPU利用率。 99.9%的时间我的线程没有处理任何东西而只是吮吸电源。我需要实现一种方法来睡眠这个线程,直到它有工作要做。所以有几个想法:

        

      使用select()来阻止。这可以基于我需要使用的计时器来阻止,并且我可以将队列消息传递实现更改为套接字   消息。所以相反,线程会打开一个客户端套接字   经理和经理会将消息通过套接字传递给   线。然后select()会一直睡到fd上有活动   或者我的计时器已经启动。

      Pro:正是我需要的功能。

      Con:对于与你共享内存的线程进行通信,套接字是不是有点繁重?

        

      使用信号系统。 (在Linux上知识渊博的人可以通过一个实现示例来管理这里...我不确定如何   这样做。)但线程可以在计时器的持续时间内休眠,并且   如果收到经理的信号,则醒来处理。

      Pro:使用共享内存维护当前实现

      Con:不确定如何实施。有没有像select()这样的函数可以使用信号而不是fds?

        

      潜在的互斥量。我可以阻止,直到经理发布了一个互斥锁。

      专业版:仍在共享内存

      Con:可能需要将计时器处理移动到管理器,这实际上不是一个选项,因为它有其他计时器和关键工作要执行。

      请推荐并随意批评。我愿意接受任何有效的选择。请注意,虽然这是在嵌入式系统上运行,但资源使用非常重要。

5 个答案:

答案 0 :(得分:5)

处理这种情况的经典工具是信号量而不是互斥量或条件变量。将它们视为从经理传递给线程的令牌。

线程可以使用sem_timedwait确保偶尔唤醒以检查数据。

请注意捕获sem_函数的错误返回,它们是可中断的。所以你可能会有比你想象的更多的唤醒。

答案 1 :(得分:4)

切换到POSIX消息队列而不是您自己的消息队列。如果经理发布请求,mq_timedreceive将返回。如果超时,则必须进行定时器轮询。已经打包了同步和阻塞。

答案 2 :(得分:3)

让每个线程在输出生产者 - 消费者队列上等待超时。如果队列等待超时,则轮询串行链路,否则处理队列上收到的命令。要从头开始形成一个合适的队列,你需要一个实际的队列(你已经拥有),一个保护队列指针/索引的互斥锁(你已经拥有)和一个信号量,初始化为0,等待(超时)功能。要向线程发送请求,请锁定互斥锁,推送请求,解锁互斥锁,发信号通知信号量。在线程中,等待信号量,如果等待返回没有超时,则锁定互斥锁,弹出请求(因为总会有一个),解锁互斥锁并处理收到的请求。如果sema等待以超时返回,则轮询串行链接。完成后,循环再次等待信号量。

要改变超时,请向线程发送一条消息,其中包含命令'EchangeWaitInterval',(比如:),以及用于后续等待的新超时间隔。

答案 3 :(得分:3)

尝试这样的事情,使用信号量:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

static sem_t s_sem;
static int iAlive = 1;

void* thFunc(void *param)
{
    printf("%s : ENTER \n", __FUNCTION__);
    while(iAlive)
    {
        printf("%s : waiting \n", __FUNCTION__);
        sem_wait(&s_sem);

        printf("%s : got a signal - doing something \n", __FUNCTION__);
        sleep(1);
    }

    printf("%s : EXIT \n", __FUNCTION__);
    return 0;
}

int main()
{
    pthread_t thread;
    sem_init(&s_sem, 0, 0);

    if(0 != pthread_create(&thread, NULL, thFunc, NULL))
    {
        printf("%s : pthread_create FAILED \n", __FUNCTION__);
        return -1;
    }

    while ( getchar() != 'q' )
    {
        printf("%s : sending signal \n", __FUNCTION__);
        sem_post(&s_sem);
    }

    iAlive = 0;
    sem_post(&s_sem);
    pthread_join(thread, NULL);
    sem_destroy(&s_sem);

    return 0;
}

如果您需要暂停,可以将sem_wait替换为sem_timedwait

答案 4 :(得分:0)

经典的pthreads方法是让你的线程在pthread_cond_wait()中阻塞,直到经理线程将消息放入队列并发出条件变量信号。在这种情况下,要及时唤醒以轮询串行设备,请改用pthread_cond_timedwait()