我發現,隨着預期的這段代碼不起作用:條件變量和#pragma包的bug
#pragma pack(push, 1)
class myclass {
protected:
bool mycrasher[1]; // with mycrasher[4] it works!
std::mutex mtx;
std::condition_variable cv;
void thread_func() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::chrono::milliseconds timeout(1000);
std::unique_lock<std::mutex> l(mtx, std::defer_lock);
while (true) {
auto now = std::chrono::system_clock::now();
l.lock();
while (true) {
std::cout << "Waiting..." << std::endl;
auto result = cv.wait_until(l, now + timeout);
std::cout << "Timed out..." << std::endl;
if (result == std::cv_status::timeout)
break;
}
l.unlock();
}
}
public:
myclass() {
std::lock_guard<std::mutex> l(mtx);
std::thread *t = new std::thread(&myclass::thread_func, this);
t->detach();
};
void start() {
std::cout << "myclass started." << std::endl;
std::cout << "sizeof(std::mutex) = " << sizeof(std::mutex) << std::endl;
std::cout << "sizeof(std::condition_variable) = " << sizeof(std::condition_variable) << std::endl;
}
};
#pragma pack(pop)
int main() {
myclass x;
x.start();
std::this_thread::sleep_for(std::chrono::seconds(60));
}
我預想的代碼等待一秒鐘的cv.wait_until
呼叫,然後重複,但只是掛在電話上。如果我刪除#pragma
指令,問題(直觀地)就會消失,因爲我正在打包互斥和CV。然而,當我運行此代碼,我得到:
myclass started.
sizeof(std::mutex) = 40
sizeof(std::condition_variable) = 48
帶或不帶pragma
,如此看來包裝是不是真正的問題。
此外,我發現如果我將mycrasher
變量與4字節邊界對齊,問題也會消失。同樣,如果我在std::condition_variable cv
聲明後移動變量,則問題消失,但在std::mutex mtx
和std::condition_variable cv
之間移動時,它仍然存在。
爲什麼當CV未正確對齊時,片段掛在cv.wait_until
調用上?預計會有性能降低,但不是一個普通的攤位。
在Debian 8系統上用g ++ 4.9.2和g ++ 6.3轉載。
'#pragma pack'只適用於* your *結構,而不適用於您在結構中使用的其他結構。看起來你不能在奇數地址上有互斥或條件變量。也許你可以告訴我們爲什麼*你想使用'#pragma pack',你試圖用它解決什麼問題,我們可以幫你解決這個問題呢? –
@Someprogrammerdude謝謝,我剛剛發現。我想了解*爲什麼它停止工作。這應該是內存密集型應用程序的一部分,因此打包數據旨在壓縮每個字節。 – xmas79
@ xmas79:這可能會適得其反。擠壓每個字節可以將不相關的數據放在同一個緩存行上。這看起來像是另一種過早優化的情況。 – MSalters