C 在linux中,如何使用EINTR诱导失败的semop调用?
我试图通过semop呼叫来诱导EINTR失败C 在linux中,如何使用EINTR诱导失败的semop调用?,c,semaphore,C,Semaphore,我试图通过semop呼叫来诱导EINTR失败 key_t semkey; int semid; struct sembuf sbuf; union semun { int val; struct semid_ds *buf; unsigned short *array; } arg; struct semid_ds ds; /* Get unique key for semaphore. */ if ((semkey = ftok("/tmp", 'a')) == (k
key_t semkey;
int semid;
struct sembuf sbuf;
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
struct semid_ds ds;
/* Get unique key for semaphore. */
if ((semkey = ftok("/tmp", 'a')) == (key_t) -1) {
perror("IPC error: ftok"); exit(1);
}
/* Get semaphore ID associated with this key. */
if ((semid = semget(semkey, 0, 0)) == -1) {
/* Semaphore does not exist - Create. */
if ((semid = semget(semkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR |
S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) != -1)
{
/* Initialize the semaphore. */
arg.val = 0;
sbuf.sem_num = 0;
sbuf.sem_op = 2; /* This is the number of runs without queuing. */
sbuf.sem_flg = 0;
if (semctl(semid, 0, SETVAL, arg) == -1
|| semop(semid, &sbuf, 1) == -1) {
perror("IPC error: semop"); exit(1);
}
}
else if (errno == EEXIST) {
if ((semid = semget(semkey, 0, 0)) == -1) {
perror("IPC error 1: semget"); exit(1);
}
goto check_init;
}
else {
perror("IPC error 2: semget"); exit(1);
}
}
else
{
/* Check that semid has completed initialization. */
/* An application can use a retry loop at this point rather than
exiting. */
check_init:
arg.buf = &ds;
if (semctl(semid, 0, IPC_STAT, arg) < 0) {
perror("IPC error 3: semctl"); exit(1);
}
if (ds.sem_otime == 0) {
perror("IPC error 4: semctl"); exit(1);
}
}
sbuf.sem_num = 0;
sbuf.sem_op = -1;
sbuf.sem_flg = SEM_UNDO;
while (semop(semid, &sbuf, 1) == -1)
{
if (errno != EINTR)
{
perror("IPC Error: semop"); exit(1);
break;
}
}
key\u t semkey;
int-semid;
结构sembuf-sbuf;
联合塞蒙{
int-val;
结构semid_ds*buf;
无符号短*数组;
}精氨酸;
结构半成品;
/*获取信号量的唯一密钥*/
如果((semkey=ftok(“/tmp,'a'))==(key\u t)-1){
perror(“IPC错误:ftok”);退出(1);
}
/*获取与此键关联的信号量ID*/
如果((semid=semget(semkey,0,0))=-1){
/*信号量不存在-创建*/
如果((semid=semget)(semkey,1,IPC|u CREAT | IPC|u EXCL | S|u IRUSR|
S|IWUSR | S|IRGRP | S|IWGRP | S|IROTH | S|IWOTH)!=-1)
{
/*初始化信号量*/
arg.val=0;
sbuf.sem_num=0;
sbuf.sem_op=2;/*这是不排队的运行次数*/
sbuf.sem_flg=0;
如果(semctl(semid,0,SETVAL,arg)=-1
||semop(semid和sbuf,1)=-1){
perror(“IPC错误:semop”);退出(1);
}
}
else if(errno==EEXIST){
如果((semid=semget(semkey,0,0))=-1){
perror(“IPC错误1:semget”);退出(1);
}
转到检查初始化;
}
否则{
perror(“IPC错误2:semget”);退出(1);
}
}
其他的
{
/*检查semid是否已完成初始化*/
/*应用程序此时可以使用重试循环,而不是
退出*/
检查初始化:
arg.buf=&ds;
if(semctl(semid,0,IPC_STAT,arg)<0){
perror(“IPC错误3:semctl”);退出(1);
}
如果(ds.sem_otime==0){
perror(“IPC错误4:semctl”);退出(1);
}
}
sbuf.sem_num=0;
sbuf.sem_op=-1;
sbuf.sem_flg=sem_UNDO;
while(semop(semid和sbuf,1)=-1)
{
如果(错误号!=EINTR)
{
perror(“IPC错误:semop”);退出(1);
打破
}
}
我得到的最多的是资源不可用或资源繁忙。我甚至尝试在两个不同的线程或两个不同的进程中运行多个信号量。但我无法获得成功。我甚至在semop等待信号量的时候尝试将信号作为SIGCHLD发送到进程
根据zwol的建议
这是我试过的,但仍然不起作用,我的意思是,我无法获得成功
int g_global_variable = 0;
void *sigusr1_block_thread (void *vargp)
{
while (1)
{
sleep (10);
printf ("sigusr1_block_thread\n");
}
return NULL;
}
void *semop_wait_thread (void *vargp)
{
int sem;
struct sembuf sops[2];
if((sem = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600))==-1){
return NULL;
}
if(semctl(sem,0,SETVAL,2)==-1){
exit(1);
}
sops[0].sem_num=0;
sops[0].sem_op=-1;
sops[0].sem_flg=0;
sops[1].sem_num=0;
sops[1].sem_op=0;
sops[1].sem_flg=0;
g_global_variable = 1;
printf ("Starting semop call \n");
if(eintr_check_semop(sem, sops,2)<0)
printf("Error semop\n");
return NULL;
}
int main()
{
pthread_t tid, tid1, tid2, tid3, tid4;
sigset_t set;
int s;
pthread_create(&tid, NULL, semop_wait_thread, NULL);
pthread_create(&tid2, NULL, semop_wait_thread, NULL);
pthread_create(&tid3, NULL, semop_wait_thread, NULL);
pthread_create(&tid4, NULL, semop_wait_thread, NULL);
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGCHLD);
s = pthread_sigmask(SIG_BLOCK, &set, NULL);
if (s != 0)
printf ("Error during pthread_sigmask");
pthread_create(&tid1, NULL, sigusr1_block_thread, NULL);
while (1)
{
sleep (1);
if (g_global_variable == 1)
{
sleep (10);
printf ("Send SIGUSR1/SIGCHLD signals \n");
/* Send signal */
pthread_kill( tid, SIGCHLD);
pthread_kill( tid2, SIGCHLD);
pthread_kill( tid3, SIGCHLD);
pthread_kill( tid4, SIGCHLD);
pthread_kill( tid1, SIGCHLD);
pthread_kill( tid1, SIGUSR1);
break;
}
else
continue;
}
pthread_join(tid, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
pthread_join(tid4, NULL);
return 0;
}
int g_global_变量=0;
void*sigusr1\u块螺纹(void*vargp)
{
而(1)
{
睡眠(10);
printf(“sigusr1块线程”);
}
返回NULL;
}
void*semop\u wait\u线程(void*vargp)
{
int-sem;
结构sembuf标准操作程序[2];
如果((sem=semget(IPC_PRIVATE,1,IPC_create | 0600))=-1){
返回NULL;
}
if(semctl(sem,0,SETVAL,2)=-1){
出口(1);
}
标准操作程序[0].sem_num=0;
标准操作程序[0].sem_op=-1;
标准操作程序[0].sem_flg=0;
标准作业程序[1]。结构数量=0;
标准操作程序[1]。结构方程组op=0;
标准操作程序[1]。sem_flg=0;
g_全局_变量=1;
printf(“启动semop调用\n”);
if(eintr\u check\u semop(sem,sops,2)eintr
仅当进程在阻塞系统调用上被阻塞时接收到信号,并且该信号有一个处理程序,并且该处理程序被配置为中断而不是重新启动系统调用时才会发生。(这一原则有一些例外,但没有一个涉及semop
)您的程序没有任何信号处理程序,因此即使您发送了信号,EINTR也不会发生
我无法直接告诉你如何做到这一点,但总体模式应该是:
为某些信号建立信号处理程序。如果您没有理由选择其他特定信号,请使用SIGUSR1
。使用sigaction
来执行此操作,而不是signal
,并且不要在sau标志中包含sau RESTART
。处理程序不必执行任何操作,它只需要存在
如果程序有多个线程,请使用pthread\u sigmask
在除一个线程外的每个线程中阻止SIGUSR1
在已解除阻止的SIGUSR1
线程中,执行将阻止的semop
操作(在不带IPC\u NOWAIT
的非零值信号量上执行“等待零”)
当上述线程在semop
上被明确阻止后,从程序内的另一个线程,使用pthread\u kill
将SIGUSR1
发送到被阻止的线程。或者,从程序外,使用常规kill
将SIGUSR1
发送到整个进程;因为信号在精确时间内被解除阻止只有一个线程,该线程将接收信号
最困难的部分是在发送信号之前确保线程在semop
上被阻塞。我不确定这在程序内部是可能的,没有争用条件。感谢您的关注;我将尝试它们