POSIX 计时器在运行几次后挂断

POSIX timer hangs up after a few runs

我在程序的主函数中创建了一个 POSIX 计时器。主程序的每个线程都在设置计时器,以便在它到期时,信号处理程序更新一个变量,该变量唤醒同一进程的下一个线程。

计时器大部分时间都可以正常工作,但并非总是如此。它有时会完成完整的执行,而在其他运行中,它会挂起。可能的原因是什么?我的怀疑与信号传递有关。

代码如下:

#define _GNU_SOURCE

#define _POSIX_C_SOURCE 199309

#include <sched.h>

#include <unistd.h>

#include <sys/wait.h>

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <unistd.h>

#include <signal.h>

#include <errno.h>

#include <semaphore.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <syscall.h>

#define NUM_THREADS 10



#define CLOCKID CLOCK_REALTIME

#define SIG SIGUSR1

int ret;

timer_t timerid;

struct sigevent sev;

struct itimerspec its;

long long freq_nanosecs;

sigset_t mask;

struct sigaction sa;



sem_t sem[NUM_THREADS];

sem_t mute;



pthread_t tid[NUM_THREADS];

int state = 0;



static void handler(int sig, siginfo_t *si, void *uc)

{

  ret = sem_post(&sem[(state+1)%NUM_THREADS]);

    if (ret)

    {

      printf("Error in Sem Post\

");

    }

    state++;

}



void *threadA(void *data_)

{ 

  int i = 0, s,n,value;



  long int loopNum;

  int turn = (intptr_t)data_;

  struct timespec tval_result,tval_result2;



  int sid = syscall(SYS_gettid);

  FILE *fp;

  fp=fopen("ipc.out","a");  

  fprintf(fp,"thread_%d %d\

",turn,sid); 

  fclose(fp); 



  int counter=0;



  while(1)

  {

    ret = sem_wait(&sem[turn]);

    if (ret)

    {

      printf("Error in Sem Post\

");

    }

    //printf("Thread # -> %d\

",turn);



    its.it_value.tv_sec = 0;

    its.it_value.tv_nsec = 14000;

    its.it_interval.tv_sec = 0;

    its.it_interval.tv_nsec = 0;



    ret = timer_settime(timerid, 0, &its, NULL);

    if ( ret < 0 )

      perror("timer_settime");



    // Some heavy work



  counter++;



  if(counter==100)

  break;

  }

  printf("finished %d\

",turn);



}



int main(int argc, char *argv[])

{

  int data = 0;

  int err,i;



  sa.sa_flags = SA_RESTART;

  sa.sa_sigaction = handler;

  sigemptyset(&sa.sa_mask);

  sigaction(SIG, &sa, NULL);



  sev.sigev_notify = SIGEV_SIGNAL;

  sev.sigev_signo = SIG;

  sev.sigev_value.sival_ptr = &timerid;

  ret = timer_create(CLOCKID, &sev, &timerid);

  if ( ret < 0 )

    perror("timer_create");



  sem_init(&sem[0], 0, 1); 

  for ( i = 1; i < NUM_THREADS; ++i)

    {

      sem_init(&sem[i], 0, 0); 

    }



  while(data < NUM_THREADS)

  {

    //create our threads

    err = pthread_create(&tid[data], NULL, threadA, (void *)(intptr_t)data);

    if(err != 0)

      printf("\

can't create thread :[%s]", strerror(err));



    data++;

  }



  pthread_exit(NULL);

}
finished 0

finished 1

finished 2

finished 3

finished 4

finished 5

finished 6

finished 7

finished 8

finished 9

static void handler(int sig, siginfo_t *si, void *uc)

{

  state++;

  ret = sem_post(&sem[(state)%NUM_THREADS]);

  if (ret)

  {

    printf("Error in Sem Post\

");

  }

}

据此,这个程序应该打印

#define _GNU_SOURCE

#define _POSIX_C_SOURCE 199309

#include <sched.h>

#include <unistd.h>

#include <sys/wait.h>

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <unistd.h>

#include <signal.h>

#include <errno.h>

#include <semaphore.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <syscall.h>

#define NUM_THREADS 10



#define CLOCKID CLOCK_REALTIME

#define SIG SIGUSR1

int ret;

timer_t timerid;

struct sigevent sev;

struct itimerspec its;

long long freq_nanosecs;

sigset_t mask;

struct sigaction sa;



sem_t sem[NUM_THREADS];

sem_t mute;



pthread_t tid[NUM_THREADS];

int state = 0;



static void handler(int sig, siginfo_t *si, void *uc)

{

  ret = sem_post(&sem[(state+1)%NUM_THREADS]);

    if (ret)

    {

      printf("Error in Sem Post\

");

    }

    state++;

}



void *threadA(void *data_)

{ 

  int i = 0, s,n,value;



  long int loopNum;

  int turn = (intptr_t)data_;

  struct timespec tval_result,tval_result2;



  int sid = syscall(SYS_gettid);

  FILE *fp;

  fp=fopen("ipc.out","a");  

  fprintf(fp,"thread_%d %d\

",turn,sid); 

  fclose(fp); 



  int counter=0;



  while(1)

  {

    ret = sem_wait(&sem[turn]);

    if (ret)

    {

      printf("Error in Sem Post\

");

    }

    //printf("Thread # -> %d\

",turn);



    its.it_value.tv_sec = 0;

    its.it_value.tv_nsec = 14000;

    its.it_interval.tv_sec = 0;

    its.it_interval.tv_nsec = 0;



    ret = timer_settime(timerid, 0, &its, NULL);

    if ( ret < 0 )

      perror("timer_settime");



    // Some heavy work



  counter++;



  if(counter==100)

  break;

  }

  printf("finished %d\

",turn);



}



int main(int argc, char *argv[])

{

  int data = 0;

  int err,i;



  sa.sa_flags = SA_RESTART;

  sa.sa_sigaction = handler;

  sigemptyset(&sa.sa_mask);

  sigaction(SIG, &sa, NULL);



  sev.sigev_notify = SIGEV_SIGNAL;

  sev.sigev_signo = SIG;

  sev.sigev_value.sival_ptr = &timerid;

  ret = timer_create(CLOCKID, &sev, &timerid);

  if ( ret < 0 )

    perror("timer_create");



  sem_init(&sem[0], 0, 1); 

  for ( i = 1; i < NUM_THREADS; ++i)

    {

      sem_init(&sem[i], 0, 0); 

    }



  while(data < NUM_THREADS)

  {

    //create our threads

    err = pthread_create(&tid[data], NULL, threadA, (void *)(intptr_t)data);

    if(err != 0)

      printf("\

can't create thread :[%s]", strerror(err));



    data++;

  }



  pthread_exit(NULL);

}
finished 0

finished 1

finished 2

finished 3

finished 4

finished 5

finished 6

finished 7

finished 8

finished 9

static void handler(int sig, siginfo_t *si, void *uc)

{

  state++;

  ret = sem_post(&sem[(state)%NUM_THREADS]);

  if (ret)

  {

    printf("Error in Sem Post\

");

  }

}

有时会这样打印,但大多数时候,程序会挂起。


信号处理程序有一个竞争条件。一旦 sem_post 被调用,其他线程之一就可以开始运行,并且它的计时器可以在当前信号处理程序完成之前触发。这将导致在另一个线程中再次调用信号处理程序。此时 state 没有被第一个线程递增,因此第二个信号处理程序调用最终会在错误的信号量上调用 sem_post

解决此问题的一种方法是确保在调用 sem_post:

之前增加 state

#define _GNU_SOURCE

#define _POSIX_C_SOURCE 199309

#include <sched.h>

#include <unistd.h>

#include <sys/wait.h>

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <unistd.h>

#include <signal.h>

#include <errno.h>

#include <semaphore.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <syscall.h>

#define NUM_THREADS 10



#define CLOCKID CLOCK_REALTIME

#define SIG SIGUSR1

int ret;

timer_t timerid;

struct sigevent sev;

struct itimerspec its;

long long freq_nanosecs;

sigset_t mask;

struct sigaction sa;



sem_t sem[NUM_THREADS];

sem_t mute;



pthread_t tid[NUM_THREADS];

int state = 0;



static void handler(int sig, siginfo_t *si, void *uc)

{

  ret = sem_post(&sem[(state+1)%NUM_THREADS]);

    if (ret)

    {

      printf("Error in Sem Post\

");

    }

    state++;

}



void *threadA(void *data_)

{ 

  int i = 0, s,n,value;



  long int loopNum;

  int turn = (intptr_t)data_;

  struct timespec tval_result,tval_result2;



  int sid = syscall(SYS_gettid);

  FILE *fp;

  fp=fopen("ipc.out","a");  

  fprintf(fp,"thread_%d %d\

",turn,sid); 

  fclose(fp); 



  int counter=0;



  while(1)

  {

    ret = sem_wait(&sem[turn]);

    if (ret)

    {

      printf("Error in Sem Post\

");

    }

    //printf("Thread # -> %d\

",turn);



    its.it_value.tv_sec = 0;

    its.it_value.tv_nsec = 14000;

    its.it_interval.tv_sec = 0;

    its.it_interval.tv_nsec = 0;



    ret = timer_settime(timerid, 0, &its, NULL);

    if ( ret < 0 )

      perror("timer_settime");



    // Some heavy work



  counter++;



  if(counter==100)

  break;

  }

  printf("finished %d\

",turn);



}



int main(int argc, char *argv[])

{

  int data = 0;

  int err,i;



  sa.sa_flags = SA_RESTART;

  sa.sa_sigaction = handler;

  sigemptyset(&sa.sa_mask);

  sigaction(SIG, &sa, NULL);



  sev.sigev_notify = SIGEV_SIGNAL;

  sev.sigev_signo = SIG;

  sev.sigev_value.sival_ptr = &timerid;

  ret = timer_create(CLOCKID, &sev, &timerid);

  if ( ret < 0 )

    perror("timer_create");



  sem_init(&sem[0], 0, 1); 

  for ( i = 1; i < NUM_THREADS; ++i)

    {

      sem_init(&sem[i], 0, 0); 

    }



  while(data < NUM_THREADS)

  {

    //create our threads

    err = pthread_create(&tid[data], NULL, threadA, (void *)(intptr_t)data);

    if(err != 0)

      printf("\

can't create thread :[%s]", strerror(err));



    data++;

  }



  pthread_exit(NULL);

}
finished 0

finished 1

finished 2

finished 3

finished 4

finished 5

finished 6

finished 7

finished 8

finished 9

static void handler(int sig, siginfo_t *si, void *uc)

{

  state++;

  ret = sem_post(&sem[(state)%NUM_THREADS]);

  if (ret)

  {

    printf("Error in Sem Post\

");

  }

}

请注意,此解决方案仍然存在一个问题。它不能确保 printf 调用的顺序正确。


相关推荐

  • Spring部署设置openshift

    Springdeploymentsettingsopenshift我有一个问题让我抓狂了三天。我根据OpenShift帐户上的教程部署了spring-eap6-quickstart代码。我已配置调试选项,并且已将Eclipse工作区与OpehShift服务器同步-服务器上的一切工作正常,但在Eclipse中出现无法消除的错误。我有这个错误:cvc-complex-type.2.4.a:Invali…
    2025-04-161
  • 检查Java中正则表达式中模式的第n次出现

    CheckfornthoccurrenceofpatterninregularexpressioninJava本问题已经有最佳答案,请猛点这里访问。我想使用Java正则表达式检查输入字符串中特定模式的第n次出现。你能建议怎么做吗?这应该可以工作:MatchResultfindNthOccurance(intn,Patternp,CharSequencesrc){Matcherm=p.matcher…
    2025-04-161
  • 如何让 JTable 停留在已编辑的单元格上

    HowtohaveJTablestayingontheeditedcell如果有人编辑JTable的单元格内容并按Enter,则内容会被修改并且表格选择会移动到下一行。是否可以禁止JTable在单元格编辑后转到下一行?原因是我的程序使用ListSelectionListener在单元格选择上同步了其他一些小部件,并且我不想在编辑当前单元格后选择下一行。Enter的默认绑定是名为selectNext…
    2025-04-161
  • Weblogic 12c 部署

    Weblogic12cdeploy我正在尝试将我的应用程序从Tomcat迁移到Weblogic12.2.1.3.0。我能够毫无错误地部署应用程序,但我遇到了与持久性提供程序相关的运行时错误。这是堆栈跟踪:javax.validation.ValidationException:CalltoTraversableResolver.isReachable()threwanexceptionatorg.…
    2025-04-161
  • Resteasy Content-Type 默认值

    ResteasyContent-Typedefaults我正在使用Resteasy编写一个可以返回JSON和XML的应用程序,但可以选择默认为XML。这是我的方法:@GET@Path("/content")@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})publicStringcontentListRequestXm…
    2025-04-161
  • 代码不会停止运行,在 Java 中

    thecodedoesn'tstoprunning,inJava我正在用Java解决项目Euler中的问题10,即"Thesumoftheprimesbelow10is2+3+5+7=17.Findthesumofalltheprimesbelowtwomillion."我的代码是packageprojecteuler_1;importjava.math.BigInteger;importjava…
    2025-04-161
  • Out of memory java heap space

    Outofmemoryjavaheapspace我正在尝试将大量文件从服务器发送到多个客户端。当我尝试发送大小为700mb的文件时,它显示了"OutOfMemoryjavaheapspace"错误。我正在使用Netbeans7.1.2版本。我还在属性中尝试了VMoption。但仍然发生同样的错误。我认为阅读整个文件存在一些问题。下面的代码最多可用于300mb。请给我一些建议。提前致谢publicc…
    2025-04-161
  • Log4j 记录到共享日志文件

    Log4jLoggingtoaSharedLogFile有没有办法将log4j日志记录事件写入也被其他应用程序写入的日志文件。其他应用程序可以是非Java应用程序。有什么缺点?锁定问题?格式化?Log4j有一个SocketAppender,它将向服务发送事件,您可以自己实现或使用与Log4j捆绑的简单实现。它还支持syslogd和Windows事件日志,这对于尝试将日志输出与来自非Java应用程序…
    2025-04-161