简体   繁体   中英

posix sem_post can't wake sem_wait where the sem init in thread. linux

This is a strange problem.I init sem and destory it first,then i init it again in a thread.then, i can't wake it again.the code is:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>

sem_t sem;
int key = 1;

static void *
wait_func()
{
    printf("i'm wait\n");
    sem_wait(&sem);
}

static void *
cancel_func(void *arg)
{
    pthread_t tid = *(pthread_t *)arg;
    if (key == 1)
    {
        sleep(1);
        key = 0;
    }
    else
        sleep(3);
    if(pthread_cancel(tid) == 0)
        printf("cancle!\n");

    sem_init(&sem, 0, 0);
    sem_destroy(&sem);
}

int
main(int argc, char *argv[])
{
    pthread_t wthread, cthread;
    pthread_attr_t attr;
    int i = 0;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    sem_init(&sem, 0, 0);

    while (i < 2)
    {
    //        sem_init(&sem, 0, 0);

        pthread_create(&wthread, &attr, wait_func, NULL);
        if (i < 1)
            pthread_create(&cthread, &attr, cancel_func, &wthread);
        if (key == 0)
        {
            sleep(2);
            if (sem_post(&sem) == 0)
                printf("post!\n");
            key = 1;
        }
        sleep(4);
        ++i;
    }
    sleep(1000);
}

however,it will be work that changed sem_init in while loop like comment!So i have straced two program,and finded 1)init in thread,sem_post didn't call sys_futex,like this:

nanosleep({2, 0}, i'm wait

{2, 0}) = 0 write(1, "post!\\n", 6post! ) = 6

2)init in main process,sem_post call sys_futex,like this:

nanosleep({2, 0}, i'm wait

{2, 0}) = 0 futex(0x600dc0, FUTEX_WAKE_PRIVATE, 1) = 1 write(1, "post!\\n", 6post! ) = 6

Then,i thought maybe this is a problem with syscall.I have used gdb to disassemble two program in sem_post. unfortunately,1)init in thread,it also call syscall in sem_post;2) compared their registry status where rip is syscall,same too.

in thread:
rax            0xca     202          //sys_futex
rbx            0x3c0e61bbc0     257939323840
rcx            0x0      0            //utime
rdx            0x1      1            //val
rsi            0x81     129          //op:private_wake
rdi            0x600dc0 6294976      //sem uaddr
in main process:
rax            0xca     202
rbx            0x3c0e61bbc0     257939323840
rcx            0x0      0
rdx            0x1      1
rsi            0x81     129
rdi            0x600da0 6294944

At last,i have no idea about this problem.Please give me some advise to find out the solution,thanks.

I think that your problem lies in the access to key . There is no guarantee that the access to shared variables is atomic. In particular the compiler might optimize the reading of a value from memory, such that it doesn't see a modification of the value that is done in another thread.

To avoid that the optimizer kicks in, you'd have to declare your key variable volatile . But I am not sure that the way you have written your program would guarantee that there are memory barriers that would guarantee that the threads are guaranteed to seen modifications and that the concurrent write is not mixing things up.

Modern C11 also has _Atomic to ensure that the access is atomic. But C11 is not yet fully implemented (there may be some compilers that have that feature). If it would be, there would be a problem with semaphores, since C11 only has mutexes and not semaphores as lock structures. How these two features would cooperate is not specified, yet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM