Ich fand heraus, dass dieses Stück Code funktioniert nicht wie beabsichtigt:Bedingungsvariable und #pragma pack Fehler
#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));
}
ich den Code erwartet eine Sekunde lang auf dem cv.wait_until
Anruf zu warten und dann wiederholen, aber ist einfach auf den Anruf hängt. Das Problem (intuitiv) geht weg, wenn ich die #pragma
Richtlinien entferne, weil ich den Mutex und den Lebenslauf verpacke. Allerdings, wenn ich diesen Code ausführen, erhalte ich:
myclass started.
sizeof(std::mutex) = 40
sizeof(std::condition_variable) = 48
mit oder ohne pragma
, so scheint es, die Verpackung nicht das eigentliche Problem ist.
Darüber hinaus entdeckte ich, dass wenn ich die mycrasher
Variable auf eine 4-Byte-Grenze ausrichten das Problem ebenfalls verschwindet. Ebenso, wenn ich die Variable nach der std::condition_variable cv
Deklaration verschiebe, verschwindet das Problem, aber wenn es zwischen std::mutex mtx
und std::condition_variable cv
bewegt wird, bleibt es bestehen.
Warum hängt das Snippet auf dem cv.wait_until
Anruf, wenn der Lebenslauf nicht richtig ausgerichtet ist? Ein Performance-Hit wäre zu erwarten, aber kein einfacher Stall.
Reproduziert mit g ++ 4.9.2 und g ++ 6.3 auf einem Debian 8-System.
Das '#pragma pack' ist nur für * Ihre * Struktur, nicht für andere, die Sie in Ihrer Struktur verwenden. Es scheint einfach, dass Sie keine Mutexe oder Bedingungsvariablen an ungeraden Adressen haben können. Vielleicht können Sie uns sagen, warum Sie '' pragma pack' verwenden wollen, welches Problem versuchen Sie damit zu lösen, und wir können Ihnen stattdessen bei diesem Problem helfen? –
@Someprogrammerdude Danke, das habe ich gerade entdeckt. Ich wollte verstehen, warum es aufhört zu arbeiten. Dies sollte Teil einer speicherintensiven Anwendung sein, so dass gepackte Daten darauf abzielen, jedes Byte zu komprimieren. – xmas79
@ xmas79: Das kann fehlschlagen. Wenn Sie jedes Byte zusammendrücken, können Sie nicht zusammenhängende Daten in derselben Cache-Zeile speichern. Dies sieht wie ein weiterer Fall einer vorzeitigen Optimierung aus. – MSalters