gpt4 book ai didi

c - 如何确保等待来自两个不同计时器的事件的线程不会错过任何事件?

转载 作者:太空宇宙 更新时间:2023-11-04 03:50:25 25 4
gpt4 key购买 nike

我想创建一个线程,等待两个定时器在它们到期时发出信号。当线程接收到信号时,它必须进行一些图像处理。我从以下代码开始。 (这是非常基本的实现,其中线程显示消息而不是进行图像处理)

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <sys/time.h>


struct itimerspec ts1,ts2;
struct sigevent se1,se2;

timer_t timerId1,timerId2;

pthread_cond_t imageProcessCond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t imageProcessMutex = PTHREAD_MUTEX_INITIALIZER;

void* imageProcessThread()
{
int status = 0;
int i = 0;

while(i<2){

status = pthread_mutex_lock (&imageProcessMutex);
if(status != 0){
perror("pthread_mutex_lock\n");
exit(status);
}

status = pthread_cond_wait (&imageProcessCond, &imageProcessMutex);
if (status != 0){
perror("pthread_cond_wait\n");
exit(status);
}

printf("signal received %s\n",__TIME__);

i++;

status = pthread_mutex_unlock (&imageProcessMutex);
if(status != 0){
perror("pthread_mutex_unlock\n");
exit(status);
}

}

}

void timerFunc1 ()
{
int status = 0;

status = pthread_mutex_lock (&imageProcessMutex);
if (status != 0){
perror("pthread_mutex_lock\n");
exit(EXIT_FAILURE);
}

printf("timer1 took lock %s\n",__TIME__);

status = pthread_cond_signal (&imageProcessCond);
if (status != 0){
perror("pthread_cond_signal\n");
exit(EXIT_FAILURE);
}

printf("timer1 signalled %s\n",__TIME__);

status = pthread_mutex_unlock (&imageProcessMutex);
if (status != 0){
perror("pthread_mutex_unlock\n");
exit(status);
}

printf("timer1 released lock %s\n",__TIME__);
}

void timerFunc2 ()
{
int status = 0;

status = pthread_mutex_lock (&imageProcessMutex);
if (status != 0){
perror("pthread_mutex_lock\n");
exit(EXIT_FAILURE);
}

printf("timer2 took lock %s\n",__TIME__);

status = pthread_cond_signal (&imageProcessCond);
if (status != 0){
perror("pthread_cond_signal\n");
exit(EXIT_FAILURE);
}

printf("timer2 signalled %s\n",__TIME__);

status = pthread_mutex_unlock (&imageProcessMutex);
if (status != 0){
perror("pthread_mutex_unlock\n");
exit(status);
}

printf("timer2 released lock %s\n",__TIME__);
}

int main()
{

int status = 0;
pthread_t tImageProcessId;

se1.sigev_notify = SIGEV_THREAD;
se1.sigev_value.sival_ptr = &timerId1;
se1.sigev_notify_function = timerFunc1;
se1.sigev_notify_attributes = NULL;

ts1.it_value.tv_sec = 20;
ts1.it_value.tv_nsec = 0;
ts1.it_interval.tv_sec = 20;
ts1.it_interval.tv_nsec = 0;

se2.sigev_notify = SIGEV_THREAD;
se2.sigev_value.sival_ptr = &timerId2;
se2.sigev_notify_function = timerFunc2;
se2.sigev_notify_attributes = NULL;

ts2.it_value.tv_sec = 20;
ts2.it_value.tv_nsec = 0;
ts2.it_interval.tv_sec = 20;
ts2.it_interval.tv_nsec = 0;

status = pthread_create((&tImageProcessId), NULL, &imageProcessThread, NULL);
if(status!= 0){
perror("pthread_create\n");
exit(EXIT_FAILURE);
}

status = timer_create(CLOCK_REALTIME, &se1, &timerId1);
if (status != 0){
perror("timer_create\n");
exit(EXIT_FAILURE);
}

status = timer_create(CLOCK_REALTIME, &se2, &timerId2);
if (status != 0){
perror("timer_create\n");
exit(EXIT_FAILURE);
}

status = timer_settime(timerId1, 0, &ts1, 0);
if (status != 0){
perror("timer_create\n");
exit(EXIT_FAILURE);
}

status = timer_settime(timerId2, 0, &ts2, 0);
if (status != 0){
perror("timer_create\n");
exit(EXIT_FAILURE);
}

sleep(80);

}

我已经为相同的时间间隔配置了两个定时器(我只是为了测试目的模拟了这种情况)在实际情况下,定时器将被配置为不同的时间间隔,但可能会出现它们都在同时)

我的理解是:

  1. 线程获取锁,进入等待状态并在内部释放锁
  2. timer1 和 timer2 几乎同时到期并且都尝试获取锁。假设定时器 1 成功获取锁,定时器 2 保持等待状态。
  3. 有锁的Timer1发出事件信号并释放锁
  4. 等待事件的线程获取锁,显示消息并释放锁,再次进入等待状态。
  5. 被定时器 1 保持在等待状态的定时器 2 获取锁,发出事件信号并释放锁6.线程再次进入画面并显示消息

但是当我运行上面的代码时,线程实际上丢失了 timer1 发出的事件信号。

这是我得到的结果

timer1 在 11:40:20 锁定

timer1 发出信号 11:40:20

timer2 在 11:40:20 锁定

timer2 发出信号 11:40:20

11:40:20 收到信号

timer2 释放锁 11:40:20

timer1 释放锁 11:40:20

timer1 发出的事件正在丢失。一旦 timer1 释放锁,timer 2 就会获取锁并且线程不会被执行。

如何确保控制从 timer1 转到线程,然后再转到 timer2?还有其他实现方法吗?请帮我解决这个问题

提前致谢

问候,阿皮萨

最佳答案

imageProcessThread 函数存在同步漏洞。从 imageProcessMutex 互斥体解锁到它的下一次锁定(第二次“while”迭代),代码是不同步的。当 imageProcessThread 不等待 imageProcessCond 时,第二个通知可能是从 TimerFunc2 函数发送的,并且此通知会消失。另一个重要的事情是虚假唤醒。即使 TimerFunc 函数不发送通知,pthread_cond_wait 也可能唤醒。它不会发生在你的情况下(根据输出),但可能会在其他情况下发生并且应该被正确对待:当通知(真实的或虚假的)到达 pthread_cond_wait 时再次检查谓词。

可以稍微更改您的代码以修复上述漏洞。主要思想是在函数之间共享局部 i 变量,让您的计时器递增它并完全保护“while”等待循环。

struct itimerspec ts1,ts2;
struct sigevent se1,se2;

timer_t timerId1,timerId2;

pthread_cond_t imageProcessCond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t imageProcessMutex = PTHREAD_MUTEX_INITIALIZER;
int i = 0;

void* imageProcessThread()
{
int status = 0;
//int i = 0;

status = pthread_mutex_lock (&imageProcessMutex);
while(i<2){
//status = pthread_mutex_lock (&imageProcessMutex);
status = pthread_cond_wait (&imageProcessCond, &imageProcessMutex);
printf("signal received %s\n",__TIME__);
//i++;
//status = pthread_mutex_unlock (&imageProcessMutex);
}
status = pthread_mutex_unlock (&imageProcessMutex);
}

void timerFunc1 ()
{
int status = 0;

status = pthread_mutex_lock (&imageProcessMutex);
i++;
printf("timer1 took lock %s\n",__TIME__);

status = pthread_cond_signal (&imageProcessCond);
printf("timer1 signalled %s\n",__TIME__);

status = pthread_mutex_unlock (&imageProcessMutex);
printf("timer1 released lock %s\n",__TIME__);
}

void timerFunc2 ()
{
int status = 0;

status = pthread_mutex_lock (&imageProcessMutex);
i++;
printf("timer2 took lock %s\n",__TIME__);

status = pthread_cond_signal (&imageProcessCond);
printf("timer2 signalled %s\n",__TIME__);

status = pthread_mutex_unlock (&imageProcessMutex);
printf("timer2 released lock %s\n",__TIME__);
}

int main()
{

int status = 0;
pthread_t tImageProcessId;

se1.sigev_notify = SIGEV_THREAD;
se1.sigev_value.sival_ptr = &timerId1;
se1.sigev_notify_function = timerFunc1;
se1.sigev_notify_attributes = NULL;

ts1.it_value.tv_sec = 20;
ts1.it_value.tv_nsec = 0;
ts1.it_interval.tv_sec = 20;
ts1.it_interval.tv_nsec = 0;

se2.sigev_notify = SIGEV_THREAD;
se2.sigev_value.sival_ptr = &timerId2;
se2.sigev_notify_function = timerFunc2;
se2.sigev_notify_attributes = NULL;

ts2.it_value.tv_sec = 20;
ts2.it_value.tv_nsec = 0;
ts2.it_interval.tv_sec = 20;
ts2.it_interval.tv_nsec = 0;

status = pthread_create((&tImageProcessId), NULL, &imageProcessThread, NULL);
status = timer_create(CLOCK_REALTIME, &se1, &timerId1);
status = timer_create(CLOCK_REALTIME, &se2, &timerId2);
status = timer_settime(timerId1, 0, &ts1, 0);
status = timer_settime(timerId2, 0, &ts2, 0);


sleep(80);

}

另一个小通知是关于

__TIME__

这是一个编译时间,因此您的输出将在每一行中显示相同的时间值。

我还建议阅读屏障同步。

关于c - 如何确保等待来自两个不同计时器的事件的线程不会错过任何事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20991097/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com