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

时间:2014-01-08 09:05:16

标签: c pthreads

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

#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几乎同时到期,两者都试图锁定。让我们假设timer1成功锁定并且计时器2保持等待状态。
  3. 具有锁定信号的Timer1发出事件并释放锁定
  4. 正在等待事件的线程接受锁定,显示消息并释放锁定并再次进入等待状态。
  5. 由定时器1保持等待状态的Timer2接受锁定,发出事件信号并释放锁定 6.Again线程进入图片并显示消息
  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释放锁,定时器2就会锁定并且线程没有被执行。

    如何确保控件从timer1转到thread然后转到timer2? 有没有其他方法来实现这个? 请帮我解决这个问题

    提前致谢

    此致 Arpitha

2 个答案:

答案 0 :(得分:1)

imageProcessThread函数具有同步违规。从imageProcessMutex互斥锁解锁到下一次锁定(第二次“while”迭代),代码不同步。 当imageProcessThread没有在imageProcessCond上等待并且此通知转到noway时,可能会从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__

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

我还建议阅读屏障同步。

答案 1 :(得分:0)

感谢您的回复

即使使用上面的代码,我也错过了一个事件。我需要一个接一个地接收事件。

如果在锁定imageProcessMutex之前再锁一次,它就可以了。这两个事件都由图像处理线程接收。请看下面的代码。

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

pthread_mutex_t mainMutex = PTHREAD_MUTEX_INITIALIZER;

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

  status = pthread_mutex_lock (&imageProcessMutex);

  while(i<2){

    status = pthread_cond_wait (&imageProcessCond, &imageProcessMutex);

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

    i++;
  }

  status = pthread_mutex_unlock (&imageProcessMutex);
}

void timerFunc1 ()
{
  int status = 0;

  status = pthread_mutex_lock (&mainMutex);

  status = pthread_mutex_lock (&imageProcessMutex);

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

  status = pthread_cond_signal (&imageProcessCond);

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

  status = pthread_mutex_unlock (&imageProcessMutex);

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

  status = pthread_mutex_unlock (&mainMutex);

}

void timerFunc2 ()
{
  int status = 0;

  status = pthread_mutex_lock (&mainMutex);

  status = pthread_mutex_lock (&imageProcessMutex);

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

  status = pthread_cond_signal (&imageProcessCond);

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

  status = pthread_mutex_unlock (&imageProcessMutex);

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

  status = pthread_mutex_unlock (&mainMutex);

}

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 = 0;
  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 = 0;
  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);
}

我得到了以下输出

timer1采取了图像处理锁定14:14:28

timer1发出信号14:14:28

收到的信号14:14:28

timer1发布图像进程锁定14:14:28

timer2采取了图像处理锁定14:14:28

timer2发出信号14:14:28

timer2发布了图像锁定14:14:28

收到的信号14:14:28

有了这个,我不会错过任何事件。

我只是想知道这是否可以在不使用pthread_cond_wait和pthread_cond_signal的情况下实现。

您提到的屏障同步主要用于在多个线程(2个或更多线程)之间进行同步。但在我的情况下,只有一个线程正在等待事件。所以我不确定屏障同步将是正确的方法。请参阅链接。

http://geekswithblogs.net/jolson/archive/2009/02/09/an-intro-to-barrier.aspx

谢谢和问候,

Arpitha