代码之家  ›  专栏  ›  技术社区  ›  doron

易失性和多线程?

  •  2
  • doron  · 技术社区  · 14 年前

    #include <pthread.h>
    #include <unistd.h>
    #include <stdio.h>
    
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    int ready = 0;
    
    wait()
    {
        int i;
        do
        {
            usleep(1000);
            pthead_mutex_lock(&mutex);
            i = ready;
            pthread_mutex_unlock(&mutex);
        } while (i == 0);   
        printf("Finished\n");
    }
    
    signal()
    {
        pthead_mutex_lock(&mutex);
        ready = 1;
        pthread_mutex_unlock(&mutex);
    }
    

    我们生成两个线程,在一个线程中调用wait,然后在另一个线程中调用signal,我们还让编译器进行积极的优化。

    现在,代码的行为是否符合预期,或者我们是否需要准备好volatile以使其正常工作?不同的编译器和库会以不同的方式处理这个问题吗?

    编辑: 我希望在互斥函数周围可能有某种东西会阻止对其本身的优化,或者编译器通常不会对轮函数调用进行优化。

    我还没有编译和测试的代码,将这样做,当我有机会。

    6 回复  |  直到 14 年前
        1
  •  2
  •   Noah Watkins    14 年前
        2
  •  2
  •   user3458 user3458    14 年前

        3
  •  1
  •   David Schwartz    13 年前

    Volatile既不是必需的,也不是足够的。所以没有理由使用它。这是不够的,因为没有标准规定它将提供线程之间的可见性。这是没有必要的,因为pthreads标准说mutex已经足够了。

    更糟糕的是,使用它意味着你是一个不称职的程序员,他试图在你的代码上撒上魔法的灰尘来让它工作。它有点像货物崇拜编程和任何人看代码会推断,你不知道它不是必需的。更糟糕的是,他们可能认为你觉得这已经足够了,他们会怀疑你写的任何其他代码,担心你用“volatile”来隐藏多线程错误,而不是修复它们。

        4
  •  0
  •   Dummy00001    14 年前

    现在,代码的行为是否符合预期,或者我们是否需要准备好volatile以使其正常工作?

    我建议使用 volatile 在这种情况下。虽然在这种情况下,它似乎是不必要的。

    我个人会加上 不稳定的

    不同的编译器和库会以不同的方式处理这个问题吗? 我希望在互斥函数周围可能有某种东西会阻止对其本身的优化,或者编译器通常不会对轮函数调用进行优化。

    在本例中,对函数(pthread\u mutex\u lock())的调用 副作用 执行环境 . 因此,编译器必须重新读取全局变量,该变量可能已被函数调用更改。

    要确定的是,您需要咨询C99的 5.1.2.3 Program execution 我从哪里借用了这个术语。让你尝一尝:

    […]访问volatile对象、修改对象、修改le或调用执行这些操作的函数都是 副作用 ,它们是执行环境状态的更改。表达式的求值可能会产生副作用。在执行序列中的特定点调用 序列点 ,之前评估的所有副作用应完整,并且没有发生后续评估的副作用(序列点概述见附录C。)

    在抽象机器中,所有的表达式都是按照语义来计算的。如果一个实际的实现能够推断出一个表达式的值没有被使用,并且没有产生任何需要的副作用(包括调用函数或访问一个易失性对象所引起的副作用),那么它就不需要对表达式的一部分进行求值

    附件C摘录:


    对参数求值后对函数的调用(6.5.2.2)。

    从那以后。

    以我的经验来看,现在的编译器已经足够聪明了,即使在积极优化时,也不会对作为全局变量的循环控制变量做任何花哨的事情。

        5
  •  -1
  •   Darron    14 年前

    在存在优化的情况下,这里需要Volatile。否则ready的读取可以合法地移出while循环。

        6
  •  -1
  •   ULysses    14 年前

    对, volatile int ready = 0; 在这里总是需要的。


    如果不希望对某些代码段进行优化,可以使用 #pragma 围绕该代码的指令(如果您的编译器支持的话)或者-这是完全可移植的-将代码移动到单独的文件中,编译这些文件而不进行任何优化。
    volatile 关键字,因为 ready