简体   繁体   English

linux如何在C语言中处理线程,管道和中断

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

How is it working with threads, pipes and interrupts with linux(pi)? 它如何与linux(pi)一起使用线程,管道和中断? I created the worker rfm69_InterruptWorker which is waiting in read-func. 我创建了正在读取功能中等待的工作程序rfm69_InterruptWorker I set a high prio to this thread. 我对此线程设置了较高的优先级。

What do i want/expected? 我想要/期望什么? I expect that when i write something to the pipe it will immediately call the thread to read from the pipe. 我希望当我向管道中写入内容时,它将立即调用线程以从管道中读取数据。 But unfortunately it will return when the main-thread goes to sleep. 但是不幸的是,它将在主线程进入睡眠状态时返回。

#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");

}

output: 输出:

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

Usually you would have synchronize your threads using condition variables or semaphores. 通常,您将使用条件变量或信号量来同步线程。 But in this case a pipe can also help to synchronize the threads, as long the communication direction remains the same, otherwise you would need 2 pipes. 但是在这种情况下,只要通信方向保持不变, pipe也可以帮助同步线程,否则您将需要2个管道。

First, I'd create the pipe before the worker thread is created. 首先,我将在创建工作线程之前创建管道。 This way, the main thread does not need to wait for the worker to create the pipe, it can start writing to it immediately. 这样,主线程无需等待工作人员创建管道,它可以立即开始对其进行写入。 We can use this behaviour to synchronize the threads because a read will block until the other end writes something in the pipe. 我们可以使用此行为来同步线程,因为read将阻塞,直到另一端在管道中写入某些内容为止。 So the worker thread essentially waits until there is data in the pipe. 因此,工作线程实际上要等到管道中有数据为止。

I've modifided your example a litte bit to demonstrate this. 我已经修改了您的示例,以证明这一点。 Note that I also use sleep in the main thread, but I don't use it to syncronize the threads but to show that the worker thread indeed waits until the main thread writes something: 请注意,我还在主线程中使用了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;
}

The output of this program is 该程序的输出是

+ 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

and as you can see from the numbers in the square brackets, the worker thread resumes working immediately after the main thread writes something in the pipe. 从方括号中的数字可以看出,工作线程在主线程向管道中写入内容后立即恢复工作。 The fact that the lines are a little bit out of sync is because printf is buffered. 这些行有点不同步的事实是因为printf被缓冲了。 But the number in the square brackets tell you exactly when which part of the threads was executed. 但是方括号中的数字可以准确告诉您何时执行了线程的哪一部分。

I don't like this approach too much, to be honest, if both the main thread and the worker have to read and write to each other, then one pipe is not enough. 老实说,我不太喜欢这种方法,如果主线程和工作人员都必须互相读写,那么一个管道是不够的。 In that case you need another pipe for the other direction or you need a better synchronization strategy. 在这种情况下,您需要另一个管道来实现另一个方向,或者需要更好的同步策略。 I'd use conditional variables, because they also work very well with multiple threads. 我将使用条件变量,因为它们在多个线程中也能很好地工作。 A similar example with condition variables 具有条件变量的类似示例

#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;
}

And the output for this is 的输出是

+ 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

One thing to notice here: the variable payload is our shared resource that is read and written by both the main and the worker thread. 这里要注意的一件事:变量payload是我们的共享资源,它由主线程和工作线程读取和写入。 Usually you would need a mutex to protect the reading and writing of the shared resource. 通常,您将需要一个互斥体来保护共享资源的读写。 Note that the main thread does not lock the mutex when writing to payload . 请注意,写入payload时,主线程不会锁定互斥体。 The reason why I can omit that here is because of the condition variable: I synchronized the threads so that only one thread at a time can write payload , so I know that when 我之所以可以省略它的原因是由于condition变量:我同步了线程,以便一次只能有一个线程可以写入payload ,所以我知道

payload = payloads[i];

is executed on the main thread, the worker thread is locked and waiting for the signal of the condition variable, so it is not writing payload at the same time as the main thread. 在主线程上执行时,工作线程被锁定并等待条件变量的信号,因此它不会与主线程同时写入payload Of course I could use a second mutex just for that, but I don't think it is necessary. 当然,我可以为此使用另一个互斥体,但是我认为没有必要。

Final remarks: 最后说明:

The correct way of defining the main is one of these three: 定义main的正确方法是以下三种方法之一:

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

Also bear in mind that the variable WorkerThreadRet is pointing to NULL . 还请记住,变量WorkerThreadRet指向NULL You would need to allocate memory for it before passing it to the thread. 在将其传递给线程之前,您需要为其分配内存。

In you code before doing 在你做代码之前

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

you might want to initialize the status variable before the write operation, otherwise you are sending some uninitialized value. 您可能要在写操作之前初始化status变量,否则将发送一些未初始化的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM