Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么编译器优化会破坏此功能?(涉及线程)_C_Multithreading_Thread Safety_Pthreads - Fatal编程技术网

C 为什么编译器优化会破坏此功能?(涉及线程)

C 为什么编译器优化会破坏此功能?(涉及线程),c,multithreading,thread-safety,pthreads,C,Multithreading,Thread Safety,Pthreads,有一个线程在循环中正常工作 void* Thread (void* nothing) { while(1) { // Sleep if requested if ( Sleep_c) Sys_Sleep (Sleep_c); Do_stuff(); if (shutdown) { shutdown_ok = 1; break;

有一个线程在循环中正常工作

void* Thread (void* nothing) {

    while(1) {
        // Sleep if requested
        if ( Sleep_c)
                Sys_Sleep (Sleep_c);

        Do_stuff();
        if (shutdown) {
            shutdown_ok = 1;
            break;
        }
    }
    return 0;
}
主线程上可能杀死它的函数

 void Shutdown (void) {

    shutdown = 1;
    while (1) // Wait for it
        if (shutdown_ok) {
            shutdown = 0;
            break;
        }
 }
现在,这可以在调试器上正常工作。但在优化代码中,它被困在[关闭函数]的while(1)循环中。为什么?


注意:我可能应该用互斥锁锁定共享变量。

因为编译器没有意识到
shutdown\u ok
将在不同线程的函数外部修改。也许编译器发现
shutdown\u ok
shutdown()
函数中总是计算为false,因此删除了
if
语句

void Shutdown (void)
{        
    shutdown = 1;
    while (1)
    {
        shutdown = 0;
    }
}
可以将变量标记为volatile,这可以向编译器提示可以以编译器无法预测的方式修改变量

C++标准7.1.5.1/8:[注释:<代码>易失性/代码>是对实现的暗示,以避免涉及对象的攻击性优化,因为对象的值可能通过实现无法检测到而改变……通常,“代码>易失性< /代码>的语义在C++中是相同的,因为它们在C.[/P>]中是相同的。 但是,编译器可能会使
volatile
变量具有标准中未指定的某些行为。例如,任何标准实际上都不能保证这种行为


由于这个原因,
volatile
不能被视为解决所有多线程问题的灵丹妙药。你最好使用适当的线程和并发原语来完成这项工作。

关机的定义是什么?它是在哪里定义的?我怀疑这需要是一个变量。

我认为'volatile'是“shutdown\u ok”的修改器应该避免这种情况。它告诉编译器,该变量可以由另一个线程修改,因此它应该始终引用它,而不是使用例如寄存器来保存其值的副本。

最有可能的原因是编译器不希望关闭解决方案是使用适当的线程同步原语,如信号量或condvar,以获得预期的行为

笔记 人们会建议关闭
volatile
,并且可以安全地假设对int的写入是原子的。这可能在大多数情况下都会有所帮助。但即使如此,您仍然可能会遇到问题。在多核计算机上,读写可能会意外地重新排序,导致您丢失一个重要信号。Intel有专门的锁指令uction可以处理这些情况,但编译器通常不会生成锁。在ARM上,您有DMB指令,但编译器也不太可能生成


底线在执行线程同步时,请使用OS原语,不要尝试推出自己的原语。这样做会出错

pthreads解决方案是使用一个条件变量:

pthread_cond_t shutdown_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t shutdown_lock = PTHREAD_MUTEX_INITIALIZER;

void* Thread (void* nothing) {

    while(1) {
        // Sleep if requested
        if ( Sleep_c)
                Sys_Sleep (Sleep_c);

        Do_stuff();

        pthread_mutex_lock(&shutdown_lock);
        if (shutdown) {
            shutdown_ok = 1;
            pthread_cond_signal(&shutdown_cond);
            pthread_mutex_unlock(&shutdown_lock);
            break;
        }
        pthread_mutex_unlock(&shutdown_lock);
    }
    return 0;
}

void Shutdown (void)
{
    pthread_mutex_lock(&shutdown_lock); 
    shutdown = 1;
    while (!shutdown_ok)
        pthread_cond_wait(&shutdown_cond, &shutdown_lock);
    shutdown = 0;
    pthread_mutex_unlock(&shutdown_lock);
}

一般来说,如果您发现自己想要忙循环,这表明您应该使用一个条件变量。

--不应该使用volatile这个修饰语volatile确实有合法的用途,比如阻止处理器缓存。@dan_waterworth
volatile
只告诉C/C++编译器必须为任何条件变量生成加载/存储读/写变量。它对处理器没有任何影响。“它告诉编译器该变量可以由另一个线程修改”否。它告诉编译器该变量可以由同一线程中的信号处理程序读取或修改。