繁体   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