C 在linux中,如何使用EINTR诱导失败的semop调用?

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

我试图通过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')) == (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
    上被阻塞。我不确定这在程序内部是可能的,没有争用条件。

    感谢您的关注;我将尝试它们