- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我遇到一种情况,需要在阻止操作之前启动到期计时器。如果在预定的时间间隔内控制仍未脱离阻止操作,那么我需要继续进行并继续其他 Activity 。该程序不应在计时器到期时终止。而是我必须执行阻塞操作之后的代码。在以下代码段中,计时器到期后,我需要转到B点而不退出。工作环境是ubuntu 18.04,代码在c中。我已经探索了setitimer
函数调用以及与信号处理程序相关的函数。但是控制不会跳过阻塞操作并继续执行后续代码。
Program to create a semaphore and setting the semaphore for use by another program.
int main(int argc,char *argv[])
{
key_t SemKey = 0x12345 ;
int SemId = -1;
int NumOfSems = 2 ;
int Flag ;
int RetStat ;
char choice = 'n' ;
struct
{
int val;
struct semid_ds *buf;
ushort array[2] ;
} Arg ;
Flag = IPC_CREAT | IPC_EXCL | 0666 ;
SemId = semget(SemKey,NumOfSems,Flag ) ;
if ( SemId == -1 )
{
perror("semget");
exit(EXIT_FAILURE);
}
Arg.array[0] = 0 ;
Arg.array[1] = 0 ;
RetStat = semctl(SemId, 0, SETALL, Arg.array);
if (RetStat == -1)
{
perror("semctl");
exit(EXIT_FAILURE);
}
printf("\nPress y or Y to continue ahead.\n");
scanf("%c",&choice);
if ( ( choice != 'y') && ( choice != 'Y'))
exit(EXIT_FAILURE);
if ( ( choice != 'y') && ( choice != 'Y'))
exit(EXIT_FAILURE);
RetStat = semctl( SemId,0, SETVAL, 1 );
if( RetStat < 0 )
{
perror( "SET SEMOP Failure: " );
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS ;
}
Program that waits for the semaphore set by the above program.
int DriverModule(int );
int main(int argc,char *argv[])
{
key_t SemKey = 0x12345 ;
int SemId ;
u_int Flag;
Flag = 0666 ;
SemId = semget( SemKey, 0, Flag );
if ( SemId == -1 )
{
perror("semget");
exit(EXIT_FAILURE);
}
DriverModule(SemId) ;
return EXIT_SUCCESS ;
}
#define MAX_ITERATIONS 100
struct itimerval timer;
int WaitForSemaphore(int ,unsigned short ) ;
void timer_handler (int signum)
{
static int count = 0;
printf ("timer expired %d times\n", ++count);
if ( count >= MAX_ITERATIONS ) // Stop the timer
{
printf("\n\nForcing Time Out Termination.....\n\n");
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
setitimer (ITIMER_VIRTUAL, &timer, NULL);
return ;
}
}
int DriverModule (int SemId)
{
struct sigaction sa;
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_flags = SA_SIGINFO;
sa.sa_handler = &timer_handler;
sigaction (SIGVTALRM, &sa, NULL);
/* Configure the timer to expire after 250 msec... */
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 250000;
/* ... and every 500 msec after that. */
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 500000;
/* Start a virtual timer. It counts down whenever this process is
executing. */
setitimer (ITIMER_VIRTUAL, &timer, NULL);
printf("\nBefore calling wait for semaphore.......\n");
// Waiting for sempahore
if( !WaitForSemaphore( SemId, 0) )
{
printf("\nUnable to get sempahore.\n");
return 0 ;
}
printf("\nAfter calling after calling wait for semaphoe module.........\n");
return 1 ;
}
int WaitForSemaphore(int SemId,unsigned short SemNum )
{
struct sembuf SemBuf;
int RetStat;
unsigned int NoOfSemOps;
SemBuf.sem_num = SemNum;
SemBuf.sem_op = -1;
SemBuf.sem_flg = 0;
NoOfSemOps = 1;
RetStat = semop( SemId, &SemBuf, NoOfSemOps );
if( RetStat < 0 )
{
if( errno == EINTR )
{
WaitForSemaphore( SemId, SemNum );
}
else
{
perror( "Wait SEMOP Failure: " );
return 0 ;
}
}
return 1 ;
}
最佳答案
好的,主要问题是使用ITIMER_VIRTUAL
。这种[类型]计数器仅在进程运行时才递减。如果进程正在执行系统调用,则该进程未运行。
因此,我们必须改用ITIMER_REAL
。而且,如果执行此操作,它将生成SIGALRM
信号[而不是SIGVTALRM
一个]。
进行这些更改之后,还有另一个问题。
必须在保护它的系统调用之后将其禁用(例如semop
)。否则,未到期的计时器(即semop
没有超时)可能会中断另一个/后续/不相关的系统调用(例如read
,write
等)。
因此,在下面的代码中,我们需要(例如):
timer_set(250000);
semop(...);
timer_set(0);
另外,请注意,可以从信号处理程序[安全地]执行有限数量的syscall [和/或库函数调用]。值得注意的是,
printf
不能在信号处理程序中使用。
errno
的原始值。
semop
之后)将看不到正确的
errno
值(例如
EINTR
),但是看不到信号处理程序选择执行的任何系统调用的
errno
值。
// create a semaphore and setting the semaphore for use by another program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <stdarg.h>
#include <time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/time.h>
#include <sys/wait.h>
int opt_n;
int opt_y;
#define MAX_ITERATIONS 100
int itype;
struct itimerval timer;
const char *pgmtail;
int WaitForSemaphore(int, unsigned short);
int DriverModule(int);
typedef long long tsc_t;
tsc_t tvzero;
tsc_t
tscget(void)
{
struct timespec ts;
tsc_t tsc;
clock_gettime(CLOCK_MONOTONIC,&ts);
tsc = ts.tv_sec;
tsc *= 1000000000;
tsc += ts.tv_nsec;
tsc -= tvzero;
return tsc;
}
double
tscsec(tsc_t tsc)
{
double sec;
sec = tsc;
sec /= 1e9;
return sec;
}
void
dbgprt(const char *fmt,...)
{
va_list ap;
char buf[1000];
char *bp = buf;
bp += sprintf(bp,"%.9f %s ",tscsec(tscget()),pgmtail);
va_start(ap,fmt);
bp += vsprintf(bp,fmt,ap);
va_end(ap);
fputs(buf,stdout);
fflush(stdout);
}
int
pgma(void)
{
key_t SemKey = 0x12345;
pgmtail = "pgma";
int SemId = -1;
int NumOfSems = 2;
int Flag = 0;
int RetStat;
#if 0
char choice = 'n';
#endif
#if 0
struct {
int val;
struct semid_ds *buf;
ushort array[2];
} Arg;
#endif
Flag |= IPC_CREAT;
//Flag |= IPC_EXCL;
Flag |= 0666;
SemId = semget(SemKey, NumOfSems, Flag);
if (SemId == -1) {
perror("semget");
exit(EXIT_FAILURE);
}
#if 0
Arg.array[0] = 0;
Arg.array[1] = 0;
RetStat = semctl(SemId, 0, SETALL, Arg.array);
if (RetStat == -1) {
perror("semctl");
exit(EXIT_FAILURE);
}
#endif
for (int phase = 0; phase <= opt_y; ++phase) {
int setval = phase;
dbgprt("pgma: SET phase=%d\n",phase);
RetStat = semctl(SemId, 0, SETVAL, setval);
if (RetStat < 0) {
perror("SET SEMOP Failure: ");
exit(EXIT_FAILURE);
}
dbgprt("USLEEP/BEF\n");
usleep(1000 * 1000);
dbgprt("USLEEP/AFT\n");
}
return EXIT_SUCCESS;
}
// Program that waits for the semaphore set by the above program.
int
pgmb(void)
{
key_t SemKey = 0x12345;
int SemId;
pgmtail = "pgmb";
// NOTE/BUG: we must add IPC_CREAT if we start pgmb first
u_int Flag = 0;
Flag |= 0666;
#if 1
Flag |= IPC_CREAT;
#endif
SemId = semget(SemKey, 2, Flag);
if (SemId == -1) {
perror("semget");
exit(EXIT_FAILURE);
}
DriverModule(SemId);
dbgprt("pgmb: complete\n");
return EXIT_SUCCESS;
}
char *
exmsg(int status)
{
static char buf[1000];
char *bp = buf;
bp += sprintf(bp,"status=[%8.8X ",status);
do {
if (WIFEXITED(status)) {
bp += sprintf(bp,"exited status=%d", WEXITSTATUS(status));
break;
}
if (WIFSIGNALED(status)) {
bp += sprintf(bp,"killed by signal %d", WTERMSIG(status));
break;
}
if (WIFSTOPPED(status)) {
bp += sprintf(bp,"stopped by signal %d", WSTOPSIG(status));
break;
}
bp += sprintf(bp,"continued");
} while (0);
bp += sprintf(bp,"]");
return buf;
}
void
testit(int newval)
{
int code;
pid_t pid;
opt_y = newval;
for (int phase = 1; phase <= 2; ++phase) {
// start the receiver
pid = fork();
if (pid != 0) {
dbgprt("testit: pid=%d\n",pid);
continue;
}
switch (phase) {
case 1:
code = pgma();
break;
case 2:
code = pgmb();
break;
default:
code = 99;
break;
}
exit(code);
}
while (1) {
int status;
pid = wait(&status);
if (pid <= 0)
break;
dbgprt("main: pid %d reaped -- %s\n",pid,exmsg(status));
}
}
int
main(int argc,char **argv)
{
//pid_t pid;
--argc;
++argv;
pgmtail = "main";
tvzero = tscget();
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'n':
opt_n = ! opt_n;
break;
}
}
opt_y = ! opt_n;
dbgprt("pgma: opt_y=%d\n",opt_y);
//testit(0);
testit(1);
return 0;
}
void
timer_set(int usec)
{
dbgprt("timer_set: SET usec=%d\n",usec);
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = usec;
/* ... and every 500 msec after that. */
// NOTE/BUG: timer must _not_ be rearmed -- can abort unrelated syscalls
timer.it_interval.tv_sec = 0;
#if 0
timer.it_interval.tv_usec = 500000;
#else
timer.it_interval.tv_usec = 0;
#endif
setitimer(itype, &timer, NULL);
}
void
timer_handler(int signum)
{
static int count = 0;
// NOTE/BUG: printf may _not_ be called from a signal handler
//dbgprt("timer expired %d times\n", ++count);
// Stop the timer
// NOTE/BUG: disabling now done elsewhere
if (count >= MAX_ITERATIONS) {
//dbgprt("Forcing Time Out Termination.....\n");
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
#if 0
setitimer(ITIMER_VIRTUAL, &timer, NULL);
#else
setitimer(ITIMER_REAL, &timer, NULL);
#endif
return;
}
}
int
DriverModule(int SemId)
{
struct sigaction sa;
sigset_t set;
int signo;
#if 0
itype = ITIMER_VIRTUAL;
signo = SIGVTALRM;
#else
itype = ITIMER_REAL;
signo = SIGALRM;
#endif
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_SIGINFO;
sa.sa_handler = &timer_handler;
sigaction(signo, &sa, NULL);
sigemptyset(&set);
sigaddset(&set,signo);
sigprocmask(SIG_UNBLOCK,&set,NULL);
/* Configure the timer to expire after 250 msec... */
// Start virtual timer. It counts down whenever this process is executing.
#if 0
setitimer(itype, &timer, NULL);
#else
timer_set(250000);
#endif
dbgprt("Before calling wait for semaphore.......\n");
// Waiting for sempahore
if (! WaitForSemaphore(SemId, 0)) {
dbgprt("Unable to get sempahore.\n");
return 0;
}
dbgprt("After calling after calling wait for semaphoe module.........\n");
return 1;
}
int
WaitForSemaphore(int SemId, unsigned short SemNum)
{
struct sembuf SemBuf;
int RetStat;
unsigned int NoOfSemOps;
while (1) {
SemBuf.sem_num = SemNum;
SemBuf.sem_op = -1;
SemBuf.sem_flg = 0;
NoOfSemOps = 1;
dbgprt("WaitFor: SEMOP\n");
RetStat = semop(SemId, &SemBuf, NoOfSemOps);
if (RetStat >= 0) {
dbgprt("WaitFor: OKAY\n");
break;
}
if (errno == EINTR) {
dbgprt("WaitFor: EINTR\n");
// do stuff here ...
// rearm timer
timer_set(250000);
continue;
}
perror("Wait SEMOP Failure: ");
exit(1);
}
// NOTE/BUG: _must_ always disable timer to prevent other syscalls from being
// interrupted
#if 1
timer_set(0);
#endif
return 1;
}
0.000000332 main pgma: opt_y=1
0.000182324 main testit: pid=849558
0.000267203 main testit: pid=849559
0.000830005 pgma pgma: SET phase=0
0.000847541 pgmb timer_set: SET usec=250000
0.000882037 pgma USLEEP/BEF
0.000891077 pgmb Before calling wait for semaphore.......
0.000895977 pgmb WaitFor: SEMOP
0.250932859 pgmb WaitFor: EINTR
0.250950128 pgmb timer_set: SET usec=250000
0.250956676 pgmb WaitFor: SEMOP
0.500996272 pgmb WaitFor: EINTR
0.501014687 pgmb timer_set: SET usec=250000
0.501021903 pgmb WaitFor: SEMOP
0.751066428 pgmb WaitFor: EINTR
0.751089504 pgmb timer_set: SET usec=250000
0.751097693 pgmb WaitFor: SEMOP
1.000970921 pgma USLEEP/AFT
1.000987303 pgma pgma: SET phase=1
1.001001916 pgma USLEEP/BEF
1.001046071 pgmb WaitFor: OKAY
1.001055982 pgmb timer_set: SET usec=0
1.001062505 pgmb After calling after calling wait for semaphoe module.........
1.001066632 pgmb pgmb: complete
1.001210687 main main: pid 849559 reaped -- status=[00000000 exited status=0]
2.001078396 pgma USLEEP/AFT
2.001269995 main main: pid 849558 reaped -- status=[00000000 exited status=0]
- Why re-arming the timer is required inside
WaitForSemaphore
?
printf
调用(由于信号安全问题,我们必须这样做),作为副作用,
count
的增量无效。
printf
,没有意识到副作用“破坏了”了处理者的撤防代码。一段时间后,我意识到自己做了什么并想要这种效果(即让处理程序“什么也不做”)。
EINTR
错误-这是我们真正想要的]以外,什么也不做。
#if 0
注释掉所有代码]。
count++
)中放入 Activity /必需的代码[
printf
]。因此,
printf(...,count++);
最好是:
printf(...); count++;
这是一种体系结构选择,可以使用基准代码(非处理程序代码)来控制布/撤防。这是因为基线不知道处理程序是否做过任何事情,因此无论如何它都必须明确地进行撤防(以防止计时器/信号在等待循环代码之外触发)。
- Why
usleep
is required insidepgma
module?
pgmb
同时查看对
semop
的超时调用条件和用于测试/验证目的的正常条件。在普通/生产代码中,无需
pgma
进休眠眠状态。
pgma
将
0
值发布到信号量。然后睡眠1秒钟(1000毫秒)。
pgmb
启动时,它将看到此
0
值[和〜250毫秒后超时]。
pgmb
将以此循环约4次,直到
pgma
唤醒并发布
1
值[正常完成
pgmb
的
semop
为止]。
pgmb
来体验失败/超时情况和正常/成功情况。
semop
中
pgmb
的等待循环]对于所有可能的模式/状态都是正确的。
关于c - 在C/Linux中,计时器到期后如何执行代码发布阻止操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63729514/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
Linux 管道可以缓冲多少数据?这是可配置的吗? 如果管道的两端在同一个进程中,但线程不同,这会有什么不同吗? 请注意:这个“同一个进程,两个线程”的问题是理论上的边栏,真正的问题是关于缓冲的。 最
我找到了here [最后一页] 一种有趣的通过 Linux 启动 Linux 的方法。不幸的是,它只是被提及,我在网上找不到任何有用的链接。那么有人听说过一种避免引导加载程序而使用 Linux 的方法
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我试图了解 ld-linux.so 如何在 Linux 上解析对版本化符号的引用。我有以下文件: 测试.c: void f(); int main() { f(); } a.c 和 b.c:
与 RetroPie 的工作原理类似,我可以使用 Linux 应用程序作为我的桌面环境吗?我实际上并不需要像实际桌面和安装应用程序这样的东西。我只需要一种干净简单的方法来在 RaspberryPi 上
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
有什么方法可以覆盖现有的源代码,我应该用 PyQt、PyGTK、Java 等从头开始构建吗? 最佳答案 如果您指的是软件本身而不是它所连接的存储库,那么自定义应用程序的方法就是 fork 项目。据我所
我的情况是:我在一个磁盘上安装了两个 linux。我将第一个安装在/dev/sda1 中,然后在/dev/sda2 中安装第二个然后我运行第一个系统,我写了一个脚本来在第一个系统运行时更新它。
我在 i2c-0 总线上使用地址为 0x3f 的系统监视器设备。该设备在设备树中配置有 pmbus 驱动程序。 问题是,加载 linux 内核时,这个“Sysmon”设备没有供电。因此,当我在总线 0
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
我正试图在 linux 模块中分配一大块内存,而 kalloc 做不到。 我知道唯一的方法是使用 alloc_bootmem(unsigned long size) 但我只能从 linux 内核而不是
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我有 .sh 文件来运行应用程序。在该文件中,我想动态设置服务器名称,而不是每次都配置。 我尝试了以下方法,它在 CentOS 中运行良好。 nohup /voip/java/jdk1.8.0_71/
我是在 Linux 上开发嵌入式 C++ 程序的新手。我有我的 Debian 操作系统,我在其中开发和编译了我的 C++ 项目(一个简单的控制台进程)。 我想将我的应用程序放到另一个 Debian 操
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
我使用4.19.78版本的稳定内核,我想找到带有企鹅二进制数据的C数组。系统启动时显示。我需要在哪里搜索该内容? 我在 include/linux/linux_logo.h 文件中只找到了一些 Log
我知道可以使用 gdb 的服务器模式远程调试代码,我知道可以调试针对另一种架构交叉编译的代码,但是是否可以更进一步,从远程调试 Linux 应用程序OS X 使用 gdbserver? 最佳答案 当然
是否有任何可能的方法来运行在另一个 Linux 上编译的二进制文件?我知道当然最简单的是在另一台机器上重建它,但假设我们唯一能得到的是一个二进制文件,那么这可能与否? (我知道这可能并不容易,但我只是
我是一名优秀的程序员,十分优秀!