我正在使用Pthread在Linux中使用多线程。

Thread1通过轮询字符设备文件来等待来自驱动程序的IRQ(我的驱动程序具有ISR以从硬件捕获IRQ)。

IRQ -----> Thread1 |-----> Thread2 |-----> Thread3 |-----> Thread4

每当Thread1收到IRQ时,我都想向Thread2Thread3Thread4发送信号以唤醒它们,然后工作。

现在,我正在尝试使用“ pthread条件变量”和“ pthread互斥量”。但是看来这不是一个好方法。

在这种情况下,同步的有效方法是什么?请帮忙。

非常感谢你。

最佳答案

据我了解,您的问题是您的子线程(线程2至4)并不总是针对Thread1收到的每个IRQ准确地唤醒一次-特别是,可能是在子线程处于接收状态时收到了IRQ已经醒来并正在处理较早的IRQ,这使得它们不会为新的IRQ所唤醒。

如果正确,那么我认为一个简单的解决方案是为每个子线程使用counting semaphore而不是条件变量。信号量是一个简单的数据结构,它维护一个整数计数器,并提供两个操作,wait / P和signal / V。 wait / P使计数器递减,如果计数器的新值是负数,它将阻塞直到计数器再次变为非负数。 signal / V递增计数器,如果计数器在递增之前为负,则唤醒等待线程(如果在wait / P中阻塞了该线程)。

这样做的效果是,在您的主线程快速连续获得多个IRQ的情况下,信号量将“记住”多个信号/ V调用(作为计数器的正整数值),并允许工作线程执行以下操作:将来可以多次调用wait / P,而不会阻塞。这样就不会“遗忘”任何信号。

Linux提供了信号量API(通过sem_init()等),但是它是为进程间同步而设计的,因此对于在单个进程内同步线程来说有点笨重。幸运的是,使用pthreads互斥锁和条件变量可以很容易地实现自己的信号量,如下所示。

请注意,在这个玩具示例中,main()线程扮演着Thread1的角色,并且每当您在终端窗口中按回车键时,它就会假装已收到IRQ。子线程扮演着Threads2-4的角色,并且每次Thread1发出信号时,它们都会假装完成一秒钟的“工作”。特别要注意的是,如果连续多次按回车键,则子线程将始终执行那么多的“工作单元”,即使它们每秒只能执行一个工作单元。

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

struct example_semaphore
{
   pthread_cond_t cond;
   pthread_mutex_t mutex;
   int count;  // acccess to this is serialized by locking (mutex)
};

// Initializes the example_semaphore (to be called at startup)
void Init_example_semaphore(struct example_semaphore * s)
{
   s->count = 0;
   pthread_mutex_init(&s->mutex, NULL);
   pthread_cond_init(&s->cond, NULL);
}

// V:  Increments the example_semaphore's count by 1.  If the pre-increment
//     value was negative, wakes a process that was waiting on the
//     example_semaphore
void Signal_example_semaphore(struct example_semaphore * s)
{
   pthread_mutex_lock(&s->mutex);
   if (s->count++ < 0) pthread_cond_signal(&s->cond);
   pthread_mutex_unlock(&s->mutex);
}

// P:  Decrements the example_semaphore's count by 1.  If the new value of the
//     example_semaphore is negative, blocks the caller until another thread calls
//     Signal_example_semaphore()
void Wait_example_semaphore(struct example_semaphore * s)
{
   pthread_mutex_lock(&s->mutex);
   while(--s->count < 0)
   {
      pthread_cond_wait(&s->cond, &s->mutex);
      if (s->count >= 0) break;
   }
   pthread_mutex_unlock(&s->mutex);
}

// This is the function that the worker-threads run
void * WorkerThreadFunc(void * arg)
{
   int workUnit = 0;
   struct example_semaphore * my_semaphore = (struct example_semaphore *) arg;
   while(1)
   {
      Wait_example_semaphore(my_semaphore);  // wait here until it's time to work
      printf("Thread %p: just woke up and is working on work-unit #%i...\n", my_semaphore, workUnit++);
      sleep(1);  // actual work would happen here in a real program
   }
}

static const int NUM_THREADS = 3;

int main(int argc, char ** argv)
{
   struct example_semaphore semaphores[NUM_THREADS];
   pthread_t worker_threads[NUM_THREADS];

   // Setup semaphores and spawn worker threads
   int i = 0;
   for (i=0; i<NUM_THREADS; i++)
   {
      Init_example_semaphore(&semaphores[i]);
      pthread_create(&worker_threads[i], NULL, WorkerThreadFunc, &semaphores[i]);
   }

   // Now we'll pretend to be receiving IRQs.  We'll pretent to
   // get one IRQ each time you press return.
   while(1)
   {
      char buf[128];
      fgets(buf, sizeof(buf), stdin);
      printf("Main thread got IRQ, signalling child threads now!\n");
      for (i=0; i<NUM_THREADS; i++) Signal_example_semaphore(&semaphores[i]);
   }
}

关于c - C Linux中的Pthread信令,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57898839/

10-11 21:45