问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

linux alarm 能在线程中用吗

发布网友 发布时间:2022-05-25 15:58

我来回答

2个回答

热心网友 时间:2023-11-28 09:29

  不管是在进程还是线程,很多时候我们都会使用一些定时器之类的功能,这里就定时器在多线程的使用说一下。首先在linux编程中定时器函数有alarm()和setitimer(),alarm()可以提供一个基于秒的定时功能,而setitimer可以提供一个基于微妙的定时功能。

  alarm()原型:
  #include <unistd.h>
  unsigned int alarm(unsigned int seconds);

  这个函数在使用上很简单,第一次调用这个函数的时候是设置定时器的初值,下一次调用是重新设置这个值,并会返回上一次定时的剩余时间。

  setitimer()原型:
  #include <sys/time.h>
  int setitimer(int which, const struct itimerval *value,struct itimerval *ovalue);

  这个函数使用起来稍微有点说法,首先是第一个参数which的值,这个参数设置timer的计时策略,which有三种状态分别是:

  ITIMER_REAL:使用系统时间来计数,时间为0时发出SIGALRM信号,这种定时能够得到一个精准的定时,当然这个定时是相对的,因为到了微秒级别我们的处理器本身就不够精确。

  ITIMER_VIRTUAL:使用进程时间也就是进程分配到的时间片的时间来计数,时间为0是发出SIGVTALRM信号,这种定时显然不够准确,因为系统给进程分配时间片不由我们控制。

  ITIMER_PROF:上面两种情况都能够触发

  第二个参数参数value涉及到两个结构体:

  struct itimerval {
  struct timeval it_interval; /* next value */
  struct timeval it_value; /* current value */
  };

  struct timeval {
  long tv_sec; /* seconds */
  long tv_usec; /* microseconds */
  };

  在结构体itimerval中it_value是定时器当前的值,it_interval是当it_value的为0后重新填充的值。而timeval结构体中的两个变量就简单了一个是秒一个是微秒。

  上面是这两个定时函数的说明,这个函数使用本不是很难,可以说是很简单,但是碰到具体的应用的时候可能就遇到问题了,在多进程编程中使用一般不会碰到什么问题,这里说的这些问题主要体现在多线程编程中。比如下面这个程序:

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

  void sig_handler(int signo)
  {
  alarm(2);
  printf("alarm signal\n");
  }

  void *pthread_func()
  {
  alarm(2);
  while(1)
  {
  pause();
  }
  }

  int main(int argc, char **argv)
  {
  pthread_t tid;
  int retval;

  signal(SIGALRM, sig_handler);

  if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
  {
  perror("pthread_create");
  exit(-1);
  }

  while(1)
  {
  printf("main thread\n");
  sleep(10);
  }
  return 0;
  }
  这个程序的理想结果是:
  main thread
  alarm signal
  alarm signal
  alarm signal
  alarm signal
  alarm signal
  main thread
  可事实上并不是这样的,它的结果是:
  main pthread
  alarm signal
  main pthread
  alarm signal
  main pthread

  为什么会出现这种情况呢?是因为发送给工作线程的信号中断的主线程的sleep,并且这个中情况只影响主线程而不会影响到其他的工作线程。我们怎么才能解决这种问题呢,最简单的方法是修改这个程序,修改这个线程主线程使用alarm,工作线程使用sleep。这样就能够达到我们的要求,但是有时候有不能简单的这样操作。所以我们就需要进一步的修改我们的程序。在这里我第一个想到的是使用signal(SIGALRM, SIG_IGN),可是这个是设置整个进程对这个信号的响应方式,经过测试也确实不能完成我期望的功能,那么怎么办呢?有这样一个函数pthread_sigmask,线程中的信号屏蔽,函数的原型及相关函数为:

  #include <signal.h>
  int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
  函数中第一个参数how有三个值SIG_BLOCK、SIG_SETMASK和SIG_UNBLOCK这里我们是用第二个值SIG_SETMASK
  int sigemptyset(sigset_t *set);/*清除信号集合set*/
  int sigaddset(sigset_t *set, int signum); /*添加信号signum到信号集set中*/
  然后我们改造我们的程序为:
  #include <pthread.h>
  #include <signal.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <sys/time.h>

  void sig_handler(int signo)
  {
  alarm(2);
  printf("alarm signal\n");
  }

  void *pthread_func()
  {
  alarm(2);
  while(1)
  {
  pause();
  }
  }

  int main(int argc, char **argv)
  {
  pthread_t tid, tid_1;
  int retval;

  signal(SIGALRM, sig_handler);

  if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
  {
  perror("pthread_create");
  exit(-1);
  }

  sigset_t sigset;
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGALRM);
  pthread_sigmask(SIG_SETMASK,&sigset,NULL);

  while(1)
  {
  printf("main pthread\n");
  sleep(10);
  }
  return 0;
  }

  这个时候我们就能够看到我们想要的结果了。

  这里再附一个setitimer的使用范例:

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

  struct itimerval timerval;
  void sig_handler(int signo)
  {
  printf("alarm signal\n");
  }
  void *pthread_func()
  {

  setitimer(ITIMER_REAL, &timerval, NULL);
  while(1)
  {
  pause();
  }
  }

  int main(int argc, char **argv)
  {
  pthread_t tid;
  int retval;
  timerval.it_interval.tv_sec = 2;
  timerval.it_interval.tv_usec = 0;
  timerval.it_value.tv_sec = 2;
  timerval.it_value.tv_usec = 0;

  signal(SIGALRM, sig_handler);

  if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
  {
  perror("pthread_create");
  exit(-1);
  }

  sigset_t sigset;
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGALRM);
  pthread_sigmask(SIG_SETMASK,&sigset,NULL);

  while(1)
  {
  printf("main thread\n");
  sleep(5);
  }
  return 0;
  }

热心网友 时间:2023-11-28 09:29

肯定可以啊
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
什么叫补按揭 后按揭贷款什么意思 买房者续按揭有什么危害 加按揭是什么意思 八月中国最凉快的地方 八月份哪里最凉快,去哪旅游好?美丽的地方 乱字同韵字是什么意思 华硕笔记本电脑触摸板怎么开笔记本电脑触摸板怎么开启和关闭_百度知 ... 陕西职务侵占案立案准则 结婚后我的恋情维系了十年,怎么做到的? 三匹的美的空调外机但安装工用的二匹的支架,这样危险吗? 精液正常的颜色是?? 系统核心启动项慢!开机要2分钟!怎样解决win7? 小米怎么用recovery模式刷机 如何发现别人登录你的 一个可以两个人同时用吗?微信可以看到对方和别人聊天吗_百度问一问 一个手机如何同时登录两个? 你好,请问下有办法知道两个是否是同一个人使用的呢? 别人花钱查我手机,能查到我有两个吗,其中有一个他不知道,是同一个手机切换登陆的微信 明明知道一个手机上过两个,怎么么能查到领一个号 别人花钱查我手机,能查到有两个吗,其中有一个不知道,是同一个手机切换登陆的,能查到吗 有两个在同一个手机上聊天,别人会不会知道?能查的出来吗? 怎么知道一个人有多个 一个人如果有两个 我知道一个 怎么才能查到另一个- 问一问 可以办公的咖啡厅叫什么 怎么查一个人在同一个群里有两个 韩国咖啡厅 全智贤代言的【咖啡滴乐cafedroptop】咖啡厅!国内有店铺吗? 别人有两个,一个我知道一个我不知道,我要怎样才能知道另一个? 求悲伤黑暗的女生网名 韩国明星经营的咖啡店有哪些?都在哪里 精液颜色与状态 公猪精液的颜色如何判定? 为什么玩CF会出现客户端服务错误 穿越火线 为什么一进游戏就显示客户端错误代码? cf客户端错误提示错误代码:28_3是怎么回事? 穿越火线为什么总是出现客户端错误 遮蔽保护带(薄膜)需要防火吗? 海信电视HZ55S7E带开机密码吗? 怎样挑选汽车隔热膜?3m的隔热膜好不好啊, 谁对太阳膜有更多的认识,对雷朋铂金、杜邦至尊和锐森双层电镀隔热膜比较了解,有谁知道哪家太阳膜不错? 舒热佳太阳膜质量怎么样?和龙膜。3M相比哪个更好 坎公骑冠剑未来公主队伍搭配 有规律重视哪里可以改善中枢神经系统的积极适应,动作控制力增强? 经常参加体育锻炼和体力劳动,为什么能加强神经系统的功能 神经系统的主要功能 研究生考试是什么时候啊? 微信建群怎么可以加40人以上 宁内蒙医科大学大学临床医学2021考研调剂线 宝宝吃星鲨过敏,有没有啥好的维生素AD推荐的? 持高级教师资格证可以报考幼师吗