我正在使用Pthread
在Linux中使用多线程。Thread1
通过轮询字符设备文件来等待来自驱动程序的IRQ(我的驱动程序具有ISR以从硬件捕获IRQ)。IRQ -----> Thread1 |-----> Thread2 |-----> Thread3 |-----> Thread4
每当Thread1
收到IRQ时,我都想向Thread2
,Thread3
和Thread4
发送信号以唤醒它们,然后工作。
现在,我正在尝试使用“ 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/