代码之家  ›  专栏  ›  技术社区  ›  2trill2spill

atomic_bool值更新,其他进程看不到

  •  4
  • 2trill2spill  · 技术社区  · 11 年前

    我有一个程序,它有两个进程与共享内存通信。在ctrl-c上,我希望两个进程都退出。我正在使用 atomic_bool 变量stop,通知进程保持循环或在设置为true时退出。然而,当 原子布尔 变量stop设置为true,则其他进程看不到更改。这意味着它仍然打印出0而不是1,但进行更改的过程显示为1。那么为什么第二个过程没有看到从false到true的更改?

    Control-c无法终止进程,因此使用 killall 相反

    #include <string.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <signal.h>
    #include <stdbool.h>
    #include <stdatomic.h>
    #include <sys/mman.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <errno.h>
    
    struct shared_map
    {
    
        atomic_bool stop;
    
    };
    
    struct shared_map *map;
    
    int compare_and_swap_loop(atomic_bool target, int value)
    {
        /* Loop until we can succesfully update the the value. */
        while(1)
        {
            /* Grab a snapshot of the value that need to be updated. */
            bool snapshot = atomic_load(&target);
    
            if(atomic_compare_exchange_weak(&target, &snapshot, value) == true)
            {
                /* We succesfully updated the value let's exit this loop and return. */
                break;
            }
        }
    
       printf("result: %d\n", atomic_load(&target));
    
        return 0;
    }
    
    static void ctrlc_handler(int sig)
    {
        compare_and_swap_loop(&map->stop, true);
    
        return;
    }
    
    void setup_signal_handler(void)
    {
        (void) signal(SIGINT, ctrlc_handler);
    
        return;
    }
    
    static int create_shared(void **pointer, int size)
    {
        *pointer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
        if(*pointer == MAP_FAILED)
        {
            printf("mmap: %s\n", strerror(errno));
            return -1;
        }
    
        return 0;
    }
    
    static void loop(void)
    {
        /* Set up signal handler. */
        setup_signal_handler();
    
        /* Check if we should stop or continue running. */
        while(atomic_load(&map->stop) == false)
        {
            sleep(2);
    
            printf("map->stop: %d\n", atomic_load(&map->stop));
        }
    
        return;
    }
    
    int main(void)
    {
        int rtrn;
        pid_t pid;
    
        rtrn = create_shared((void **)&map, sizeof(struct shared_map));
        if(rtrn < 0)
        {
            printf("Can't create shared memory\n");
            return -1;
        }
    
        atomic_init(&map->stop, false);
    
        pid = fork();
        if(pid == 0)
        {
            loop();
    
            _exit(0);
        }
        else if(pid > 0)
        {
            int status;
    
            waitpid(pid, &status, 0);
    
            return 0;
        }
        else
        {
            printf("fork: %s\n", strerror(errno));
            return -1;
        }
    
        return 0;
    }
    
    2 回复  |  直到 11 年前
        1
  •  6
  •   nos    11 年前

    您正在将原子变量的副本传递给 compare_and_swap_loop 函数,这对您没有任何好处-您需要处理流程之间共享的相同值。

    你需要这样做:

    int compare_and_swap_loop(atomic_bool *target, int value)
    {
       /* Loop until we can succesfully update the the value. */
       while(1)
       {
        /* Grab a snapshot of the value that need to be updated. */
           bool snapshot = atomic_load(target);
    
           if(atomic_compare_exchange_weak(target, &snapshot, value) == true)
           {
            /* We succesfully updated the value let's exit this loop and return. */
            break;
           }
       }
    
       printf("result: %d\n", atomic_load(target));
    
       return 0;
    }
    
        2
  •  0
  •   user3629249    11 年前

    以下代码是在不使用“atomic_*”命令的情况下编写的 但确实显示了流程中的错误。

    大多数情况下,需要杀死孩子pid,而不是父母pid

    以下代码显示子pid,因此很容易找到

    #define _GNU_SOURCE
    
    #include <string.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <signal.h>
    #include <stdbool.h>
    //#include <stdatomic.h>
    #include <sys/mman.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <errno.h>
    
    struct shared_map
    {
        bool stop;
    };
    
    struct shared_map *map;
    
    int compare_and_swap_loop( bool *target )
    {
        /* Loop until we can succesfully update the the value. */
        while(1)
        {
            /* Grab a snapshot of the value that need to be updated. */
            bool snapshot = *target;
    
            if(snapshot)
            {
                /* We succesfully updated the value let's exit this loop and return. */
                break;
            }
        }
    
        return 0;
    }
    
    static void ctrlc_handler(int sig)
    {
        if( SIGINT==sig)
        compare_and_swap_loop(&map->stop);
    
        return;
    }
    
    void setup_signal_handler(void)
    {
        (void) signal(SIGINT, ctrlc_handler);
    
        return;
    }
    
    static int create_shared(void **pointer, size_t size)
    {
        *pointer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
        if(*pointer == MAP_FAILED)
        {
            perror("mmap failed");
            return -1;
        }
    
        return 0;
    }
    
    static void loop(void)
    {
        /* Set up signal handler. */
        setup_signal_handler();
    
        /* Check if we should stop or continue running. */
        while(!map->stop)
        {
            sleep(2);
    
            printf("map->stop: %d\n", map->stop);
        }
    
        return;
    }
    
    int main(void)
    {
        int rtrn;
        pid_t pid;
    
        printf( "entered Main\n");
    
        rtrn = create_shared((void **)&map, sizeof(struct shared_map));
        if(rtrn < 0)
        {
            printf("Can't create shared memory\n");
            return -1;
        }
    
        map->stop = false;
    
        pid = fork();
        if(pid == 0)
        { //then child
            printf( "child process\n");
            loop();
    
            _exit(0);
        }
        else if(pid > 0)
        { // then parent
            int status;
            printf( "parent process\n");
            printf( "child Pid: %d\n", pid);
    
            waitpid(pid, &status, 0);
    
            return 0;
        }
        else
        { // else, fork failed
            perror("fork failed");
            return -1;
        }
    
        return 0;
    }