编译器优化和线程
compiler optimisations and threads
我有一个在线程中执行任务的程序,我希望可以选择通过按键提前终止。这是一个 MWE:
#include <chrono>
#include <iostream>
#include <thread>
int main(int argc, char *argv[]) {
char endChar = 0;// endChar is only written by keyboard thread
std::thread kbth([&endChar]() { std::cin >> endChar; });//this thread monitors the keyboard
kbth.detach();
std::chrono::seconds run_t{15};
bool running = true; // running could be written by main and task thread at
// same time (unlikely)
std::mutex task_mtx; // so protect with mutex
std::thread task([&running, &run_t, &task_mtx]() {
std::this_thread::sleep_for(run_t);
std::scoped_lock lock{task_mtx};
running = false;
}); //this thread performs the task
task.detach();
while (running) { //running is false when the task ends
if (endChar == 42) { // 42=*
std::cout << "key pressed" << std::endl;
std::scoped_lock lock{task_mtx};
running = false; //or when * is entered
break;
}
}
std::cout << "bye" << std::endl;
}
这在没有编译器优化的情况下工作正常,但在优化时失败了。请有人能帮我理解为什么会这样吗?根据 this ,只要不改变“程序的可观察行为”,编译器就可以优化代码。因此,当优化开启时失败时,这不算改变可观察到的行为吗?我尝试使用 g++ 和 cl,总结:
// clang-format off
// g++ version 11.2.1 fedora 64bit
// g++ -O0 -std=c++1z ../src/kbthread.cpp -o kbthread -l pthread //OK, exits gracefully when done or when key pressed
// g++ -O1 -std=c++1z ../src/kbthread.cpp -o kbthread -l pthread //fail, hang
// g++ -O2 -std=c++1z ../src/kbthread.cpp -o kbthread -l pthread //fail, hang
// cl version 19.29.30133 for x64 windows
// cl /EHsc -std:c++17 -Od -MD ../src/kbthread.cpp //OK, exits gracefully when done or when key pressed
// cl /EHsc -std:c++17 -O1 -MD ../src/kbthread.cpp // fail, immediately prints "key pressed\nbye"
// cl /EHsc -std:c++17 -O2 -MD ../src/kbthread.cpp // fail, immediately prints "key pressed\nbye"
// clang-format on
好的,正如下面的评论指出的线程问题@François Andrieux 我已经用下面的代码使用原子“修复”了它:
int main(int argc, char *argv[]) {
std::atomic_char endChar{0};
std::thread kbth([&endChar]() { // this thread monitors the keyboard
char buff = 0;
std::cin >> buff;
endChar = buff;
});
kbth.detach();
std::chrono::seconds run_t{10};
std::atomic_bool running{true};
std::thread task([&running, &run_t]() { // this thread performs the task
std::this_thread::sleep_for(run_t);
running = false;
});
task.detach();
while (running.load()) { // running is false when the task ends, so the program ends
if (endChar.load() == 42) { // 42=*
std::cout << "key pressed" << std::endl;
running = false; // or when * is entered, so the program ends early
break;
}
}
std::cout << "bye" << std::endl;
}
仍然不确定分离的使用,但现在似乎工作正常。
我有一个在线程中执行任务的程序,我希望可以选择通过按键提前终止。这是一个 MWE:
#include <chrono>
#include <iostream>
#include <thread>
int main(int argc, char *argv[]) {
char endChar = 0;// endChar is only written by keyboard thread
std::thread kbth([&endChar]() { std::cin >> endChar; });//this thread monitors the keyboard
kbth.detach();
std::chrono::seconds run_t{15};
bool running = true; // running could be written by main and task thread at
// same time (unlikely)
std::mutex task_mtx; // so protect with mutex
std::thread task([&running, &run_t, &task_mtx]() {
std::this_thread::sleep_for(run_t);
std::scoped_lock lock{task_mtx};
running = false;
}); //this thread performs the task
task.detach();
while (running) { //running is false when the task ends
if (endChar == 42) { // 42=*
std::cout << "key pressed" << std::endl;
std::scoped_lock lock{task_mtx};
running = false; //or when * is entered
break;
}
}
std::cout << "bye" << std::endl;
}
这在没有编译器优化的情况下工作正常,但在优化时失败了。请有人能帮我理解为什么会这样吗?根据 this ,只要不改变“程序的可观察行为”,编译器就可以优化代码。因此,当优化开启时失败时,这不算改变可观察到的行为吗?我尝试使用 g++ 和 cl,总结:
// clang-format off
// g++ version 11.2.1 fedora 64bit
// g++ -O0 -std=c++1z ../src/kbthread.cpp -o kbthread -l pthread //OK, exits gracefully when done or when key pressed
// g++ -O1 -std=c++1z ../src/kbthread.cpp -o kbthread -l pthread //fail, hang
// g++ -O2 -std=c++1z ../src/kbthread.cpp -o kbthread -l pthread //fail, hang
// cl version 19.29.30133 for x64 windows
// cl /EHsc -std:c++17 -Od -MD ../src/kbthread.cpp //OK, exits gracefully when done or when key pressed
// cl /EHsc -std:c++17 -O1 -MD ../src/kbthread.cpp // fail, immediately prints "key pressed\nbye"
// cl /EHsc -std:c++17 -O2 -MD ../src/kbthread.cpp // fail, immediately prints "key pressed\nbye"
// clang-format on
好的,正如下面的评论指出的线程问题@François Andrieux 我已经用下面的代码使用原子“修复”了它:
int main(int argc, char *argv[]) {
std::atomic_char endChar{0};
std::thread kbth([&endChar]() { // this thread monitors the keyboard
char buff = 0;
std::cin >> buff;
endChar = buff;
});
kbth.detach();
std::chrono::seconds run_t{10};
std::atomic_bool running{true};
std::thread task([&running, &run_t]() { // this thread performs the task
std::this_thread::sleep_for(run_t);
running = false;
});
task.detach();
while (running.load()) { // running is false when the task ends, so the program ends
if (endChar.load() == 42) { // 42=*
std::cout << "key pressed" << std::endl;
running = false; // or when * is entered, so the program ends early
break;
}
}
std::cout << "bye" << std::endl;
}
仍然不确定分离的使用,但现在似乎工作正常。