簡體   English   中英

我需要實現一種方法來睡眠這個線程,直到它有工作要做

[英]I need to implement a way to sleep this thread until it has work to do

好吧,所以這個問題並不完全是關於線程管理......好吧,等等。 我正在尋找這種配置的不同解決方案。 我有一些想法,但我正在尋找可以解決問題的任何解決方案。 並將權衡利弊,以實現最好的一個。

情況就是這樣。

我有一個將生成線程的管理器應用程序。 該線程將持續運行並處理通過USB連接到系統的板的串行通信。 管理器應用程序促進系統上運行的其他應用程序與此線程之間的通信。 線程需要真正執行兩件事:

  1. 在可變定時器上通過串行輪詢電路板獲取樣品數據..通常大約每分鍾一次(串行總線相當慢,波特率為4800.我無法控制這個)
  2. 促進與經理應用程序的通信。 (即其他應用程序將請求樣本數據,管理器將請求轉發給線程。線程執行操作並返回數據)

我最初的設計很簡單,很有效。 我使用隊列和互斥體來管理經線。 所以線程的邏輯如下:

  1. 初始化
  2. 雖然我們沒有收到經理的關機命令
  3. 如果我們的計時器已啟動,請在電路板上查詢數據
  4. 否則,請檢查管理器是否有消息發送到隊列。 如果是這樣,請處理它

問題是我沒有考慮CPU利用率。 99.9%的時間我的線程沒有處理任何東西而只是吮吸電源。 我需要實現一種方法來睡眠這個線程,直到它有工作要做。 所以有幾個想法:

使用select()來阻止。 這可以基於我需要使用的計時器來阻止,我可以將隊列消息傳遞實現更改為套接字消息傳遞。 相反,線程會打開一個客戶端套接字到管理器,管理器會通過套接字將消息傳遞給線程。 然后select()會睡覺,直到fd上有活動或我的計時器啟動。

親:正是我需要的功能。

Con:對於與你共享內存的線程進行通信,套接字是不是有點繁重?

使用信號系統。 (在Linux上知識淵博的人可以通過一個實現示例在這里進行管道......我不確定該怎么做。)但是線程可以在計時器的持續時間內休眠,並且如果信號是,則喚醒進行處理收到經理。

Pro:使用共享內存維護當前實現

Con:不確定如何實施。 是否有像select()這樣的函數可以使用信號而不是fds?

可能是互斥量。 我可以阻止,直到經理發布了一個互斥鎖。

專業:仍然共享內存

Con:可能需要將計時器處理移動到管理器,這實際上不是一個選項,因為它有其他計時器和關鍵工作要執行。

請推薦並隨意批評。 我願意接受任何有效的選擇。 請注意,雖然這是在嵌入式系統上運行,但資源使用至關重要。

處理這種情況的經典工具是信號量而不是互斥量或條件變量。 將它們視為從經理傳遞給線程的令牌。

線程可以使用sem_timedwait來確保sem_timedwait喚醒以檢查數據。

注意很好地捕獲sem_函數的錯誤返回,它們是可中斷的。 所以你可能會有比你想象的更多的喚醒。

切換到POSIX消息隊列而不是您自己的消息隊列。 如果經理發布請求, mq_timedreceive將返回。 如果超時,則必須進行定時器輪詢。 同步和阻塞已經打包。

讓每個線程在輸出生產者 - 消費者隊列上等待超時。 如果隊列等待超時,則輪詢串行鏈路,否則處理隊列上收到的命令。 要從頭開始形成一個合適的隊列,你需要一個實際的隊列(你已經擁有),一個保護隊列指針/索引的互斥鎖(你已經擁有)和一個信號量,初始化為0,等待(超時)功能。 要向線程發送請求,請鎖定互斥鎖,推送請求,解鎖互斥鎖,發信號通知信號量。 在線程中,等待信號量,如果等待返回沒有超時,則鎖定互斥鎖,彈出請求(因為總會有一個),解鎖互斥鎖並處理收到的請求。 如果sema等待以超時返回,則輪詢串行鏈接。 完成后,循環再次等待信號量。

要改變超時,請向線程發送一條消息,其中包含命令'EchangeWaitInterval'(例如:),以及用於后續等待的新超時間隔。

嘗試這樣的事情,使用信號量:

#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_waitsem_timedwait如果你需要超時。

經典的pthreads方法是讓你的線程在pthread_cond_wait()阻塞,直到管理器線程將消息放入隊列並發出條件變量信號。 在這種情況下,要及時喚醒輪詢串行設備,請改用pthread_cond_timedwait()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM