10

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

这是情况。

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

  1. 通过可变计时器上的串行轮询板以获取样本数据..通常大约每分钟一次(串行总线相当慢,波特率为 4800。我无法控制这个)
  2. 促进与管理器应用程序的通信。(即其他应用程序将请求样本数据,管理器将请求转发给线程。线程执行操作并返回数据)

我最初的设计很简单,而且很有效。我使用队列和互斥锁进行管理器线程通信。所以线程的逻辑如下:

  1. 初始化
  2. 虽然我们还没有收到经理的关机命令
  3. 如果我们的计时器到了,请轮询董事会以获取数据
  4. 否则,检查我们是否有经理向队列发布的消息。如果是,处理它

问题是我没有考虑 CPU 利用率。99.9% 的时间我的线程什么都不处理,只是在消耗能量。我需要实现一种方法来让这个线程休眠,直到它有工作要做。所以有几个想法:

使用 select() 来阻止。这可以根据我需要使用的计时器进行阻塞,并且我可以将队列消息传递实现更改为套接字消息传递。因此,线程将向管理器打开一个客户端套接字,而管理器将通过套接字将消息传递给线程。然后 select() 会一直休眠,直到 fd 上有活动或我的计时器到时为止。

Pro:正是我需要的功能。

缺点:对于与您已经共享内存的线程的通信,套接字不是有点繁重的处理吗?

使用信号系统。(更了解 Linux 的人可以在这里提供一个实现示例……我不确定具体该怎么做。)但是线程可以在计时器的持续时间内休眠,如果有信号则唤醒以进行处理从经理那里收到。

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

缺点:不确定如何实施。是否有像 select() 这样的函数可以处理信号而不是 fds?

可能是互斥体。我可以阻止,直到经理发布互斥锁。

优点:仍然共享内存

缺点:可能需要将计时器处理移至管理器,这确实不是一个选项,因为它还有其他计时器和关键工作要执行。

请推荐并随时批评。我对任何有效的选择持开放态度。请注意,虽然这是在嵌入式系统上运行的,但资源使用至关重要。

4

5 回答 5

5

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

该线程可以sem_timedwait用来确保不时唤醒以检查数据。

小心捕捉sem_函数的错误返回,它们是可中断的。所以你可能比你想象的要多一点。

于 2012-06-29T14:44:31.800 回答
4

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

于 2012-06-29T14:43:23.063 回答
4

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

#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

于 2012-07-02T08:04:15.273 回答
3

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

要更改超时,请使用命令“EchangeWaitInterval”(例如:)向线程发送一条消息,以及用于后续等待的新超时间隔。

于 2012-06-29T14:41:13.037 回答
0

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

于 2012-07-02T07:22:24.647 回答