簡體   English   中英

linux如何在C語言中處理線程,管道和中斷

[英]How is it working with threads, pipes and interrupts in C with linux

它如何與linux(pi)一起使用線程,管道和中斷? 我創建了正在讀取功能中等待的工作程序rfm69_InterruptWorker 我對此線程設置了較高的優先級。

我想要/期望什么? 我希望當我向管道中寫入內容時,它將立即調用線程以從管道中讀取數據。 但是不幸的是,它將在主線程進入睡眠狀態時返回。

#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>
#include <sched.h>
#include <stdint.h>
#include <stdio.h>
#include <poll.h>

int pipe_test[2];

static struct pollfd gl_pfd;

pthread_t WorkerThread;       // Thread to compute log messages
struct data* WorkerThreadRet; // Storage for thread return value


static void* rfm69_InterruptWorker(void* dummy)
{
  uint8_t status;
  uint8_t retval;
  uint32_t timeout = 0;
  struct sched_param params; // struct sched_param is used to store the scheduling priority
  int ret;

  if (pipe(pipe_test) < 0) {
    printf("pipe error\r\n");
  }

  printf("created pipe \r\n");

  gl_pfd.fd = pipe_test[0];
  gl_pfd.events = POLLIN;

  printf("setting prio\r\n");

  // We'll set the priority to the minimum
  params.sched_priority = sched_get_priority_max(SCHED_FIFO);
  // Attempt to set thread priority to the SCHED_OTHER policy
  ret = pthread_setschedparam(pthread_self(), SCHED_FIFO, &params);

  printf("before  poll/read\r\n");
  //retval = poll(&gl_pfd, 1, -1);
  //retval = poll(gl_pdf,2, -1); //When with polling gpio-pin and pipe to break
  retval = read(pipe_test[0], &status, sizeof(status));

  printf("after poll\r\n");

}


void main() {

  uint8_t status;

  pthread_create(&WorkerThread, NULL, rfm69_InterruptWorker, WorkerThreadRet);

  usleep(1000);


  printf("write to pipe\r\n");
  write(pipe_test[1], &status, sizeof(status));

  printf("Go to sleep\r\n");
  usleep(1);
  printf("back to sleep\r\n");

}

輸出:

created pipe 
setting prio
before  poll/read
write to pipe
Go to sleep
after poll
back to sleep

通常,您將使用條件變量或信號量來同步線程。 但是在這種情況下,只要通信方向保持不變, pipe也可以幫助同步線程,否則您將需要2個管道。

首先,我將在創建工作線程之前創建管道。 這樣,主線程無需等待工作人員創建管道,它可以立即開始對其進行寫入。 我們可以使用此行為來同步線程,因為read將阻塞,直到另一端在管道中寫入某些內容為止。 因此,工作線程實際上要等到管道中有數據為止。

我已經修改了您的示例,以證明這一點。 請注意,我還在主線程中使用了sleep ,但是我沒有使用它來同步線程,而是為了表明工作線程確實等到主線程寫了一些東西:

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

typedef struct th_data {
    int fd[2];
    // add other arguments as needed
} th_data;

void *myworker(void *args)
{
    int payload;
    th_data *data = args;
    time_t now;

    time_t start, stop;

    start = time(NULL);

    ssize_t ret = read(data->fd[0], &payload, sizeof payload);
    now = time(NULL);

    if(ret == -1)
    {
        perror("read, terminating worker");
        pthread_exit(0);
    }

    stop = time(NULL);

    printf("* worker [%zu]: waited %zu seconds, payload: %d\n", now, stop-start, payload);

    //////////////////

    start = time(NULL);

    ret = read(data->fd[0], &payload, sizeof payload);
    now = time(NULL);

    if(ret == -1)
    {
        perror("read, terminating worker");
        pthread_exit(0);
    }

    stop = time(NULL);

    printf("* worker [%zu]: waited %zu seconds, payload: %d\n", now, stop-start, payload);



    //////////////////

    start = time(NULL);

    ret = read(data->fd[0], &payload, sizeof payload);
    now = time(NULL);

    if(ret == -1)
    {
        perror("read, terminating worker");
        pthread_exit(0);
    }

    stop = time(NULL);

    printf("* worker [%zu]: waited %zu seconds, payload: %d\n", now, stop-start, payload);


    pthread_exit(0);
}

int main(void)
{

    pthread_t th;
    th_data data;
    time_t now;

    if(pipe(data.fd) < 0)
    {
        perror("pipe");
        return 1;
    }

    pthread_create(&th, NULL, myworker, &data);

    int payload = 88;

    printf("+ Main thread: sleep 1 second\n");
    sleep(1);

    now = time(NULL);
    printf("+ Main thread [%zu], writing...\n", now);
    write(data.fd[1], &payload, sizeof payload);

    printf("+ Main thread: sleep 2 seconds\n");
    sleep(2);

    payload = -12;
    now = time(NULL);
    printf("+ Main thread [%zu], writing...\n", now);
    write(data.fd[1], &payload, sizeof payload);

    printf("+ Main thread: sleep 3 seconds\n");
    sleep(3);

    payload = 1024;
    now = time(NULL);
    printf("+ Main thread [%zu], writing...\n", now);
    write(data.fd[1], &payload, sizeof payload);

    pthread_join(th, NULL);

    return 0;
}

該程序的輸出是

+ Main thread: sleep 1 second
+ Main thread [1524698241], writing...
+ Main thread: sleep 2 seconds
* worker [1524698241]: waited 1 seconds, payload: 88
+ Main thread [1524698243], writing...
+ Main thread: sleep 3 seconds
* worker [1524698243]: waited 2 seconds, payload: -12
+ Main thread [1524698246], writing...
* worker [1524698246]: waited 3 seconds, payload: 1024

從方括號中的數字可以看出,工作線程在主線程向管道中寫入內容后立即恢復工作。 這些行有點不同步的事實是因為printf被緩沖了。 但是方括號中的數字可以准確告訴您何時執行了線程的哪一部分。

老實說,我不太喜歡這種方法,如果主線程和工作人員都必須互相讀寫,那么一個管道是不夠的。 在這種情況下,您需要另一個管道來實現另一個方向,或者需要更好的同步策略。 我將使用條件變量,因為它們在多個線程中也能很好地工作。 具有條件變量的類似示例

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

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;

int payload; // shared resource

void *worker(void *args)
{
    int i = 0;

    int payloads[] = { 1, 3, -9};

    size_t len = sizeof payloads / sizeof payloads[0];

    int oldpayload;

    while(1)
    {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cv, &mutex);
        printf("* worker[%d]: main thread signal cond variable, payload is %d\n", i, payload);

        oldpayload = payload;

        payload = payloads[i % len];
        printf("* worker[%d]: setting payload to %d\n", i, payload);
        pthread_mutex_unlock(&mutex);


        // now waking up master
        pthread_cond_signal(&cv);

        if(oldpayload == 99)
            break;

        i++;
    }

    printf("* worker:    My work is done, bye\n");

    pthread_exit(0);
}

int main(void)
{
    pthread_t th;
    pthread_create(&th, NULL, worker, NULL);

    int payloads[] = { 19, -12, 110, 1024, 99 };

    for(size_t i = 0; i < sizeof payloads / sizeof payloads[0]; ++i)
    {
        printf("+ main[%zu]:   doing some work, setting payload to %d\n", i, payloads[i]);
        fflush(stdout);
        usleep(10000); // simulation work

        payload = payloads[i];
        pthread_cond_signal(&cv);

        // time for master to wait
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cv, &mutex);
        printf("+ main[%zu]:   worker set payload to %d\n\n", i, payload);
        fflush(stdout);
        pthread_mutex_unlock(&mutex);
    }

    pthread_join(th, NULL);

    return 0;
}

的輸出是

+ main[0]:   doing some work, setting payload to 19
* worker[0]: main thread signal cond variable, payload is 19
* worker[0]: setting payload to 1
+ main[0]:   worker set payload to 1

+ main[1]:   doing some work, setting payload to -12
* worker[1]: main thread signal cond variable, payload is -12
* worker[1]: setting payload to 3
+ main[1]:   worker set payload to 3

+ main[2]:   doing some work, setting payload to 110
* worker[2]: main thread signal cond variable, payload is 110
* worker[2]: setting payload to -9
+ main[2]:   worker set payload to -9

+ main[3]:   doing some work, setting payload to 1024
* worker[3]: main thread signal cond variable, payload is 1024
* worker[3]: setting payload to 1
+ main[3]:   worker set payload to 1

+ main[4]:   doing some work, setting payload to 99
* worker[4]: main thread signal cond variable, payload is 99
* worker[4]: setting payload to 3
* worker:    My work is done, bye
+ main[4]:   worker set payload to 3

這里要注意的一件事:變量payload是我們的共享資源,它由主線程和工作線程讀取和寫入。 通常,您將需要一個互斥體來保護共享資源的讀寫。 請注意,寫入payload時,主線程不會鎖定互斥體。 我之所以可以省略它的原因是由於condition變量:我同步了線程,以便一次只能有一個線程可以寫入payload ,所以我知道

payload = payloads[i];

在主線程上執行時,工作線程被鎖定並等待條件變量的信號,因此它不會與主線程同時寫入payload 當然,我可以為此使用另一個互斥體,但是我認為沒有必要。

最后說明:

定義main的正確方法是以下三種方法之一:

  • int main(void);
  • int main(int argc, char **argv);
  • int main(int argc, char *argv[]);

還請記住,變量WorkerThreadRet指向NULL 在將其傳遞給線程之前,您需要為其分配內存。

在你做代碼之前

write(pipe_test[1], &status, sizeof(status));

您可能要在寫操作之前初始化status變量,否則將發送一些未初始化的值。

暫無
暫無

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

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