Bug in Windows (10) gefunden?
-
Bonita.M schrieb:
hustbaer schrieb:
Lol
Nein.
Du hast es nicht verstanden.
Wait
aufzurufen während man die Mutex doppelt gelockt hat ist ein Anwendungsfehler.Erstens ist kein doppeltes Locken möglich; es gibt immer nur einen Owner.
Natürlich ist es das, dafür hast du ja extra
m_dwRecursionCount
eingebaut. Verstehst du wirklich nicht was ich schreibe oder willst du mich bloss verarschen?Bonita.M schrieb:
Und zweitens hat der Thread bis zum InterlockedAdd den Besitz an dem Mutex, und kann bis dahin m_dwRecursionCount und m_dwOwningId ändern.
Ja, Mädchen. Ich versteh' dich schon. Du mich bloss nicht. Steig mal von deinem hohen Ross runter und lies Beiträge von anderen mal unter der Annahme dass sie vielleicht a) nicht blöd sind und b) Recht haben könnten.
Dashier geht mit deinem Code:cs.Enter(); cs.Enter(); cs.Wait(); cs.Leave(); cs.Leave();
Während des Wait() kann die CV dabei von anderen Threads gelockt werden. UND DAS IST EIN FEHLER!
Bonita.M schrieb:
... Dann ist nur deine
cv
Klasse ein nutzloses Teil von dem man besser die Finger lassen sollte.Der Code is 100% fehlerfrei. Ich habe ihn mit einer Queue die von einem Haupt-Thread 1.000 Worker-Threads füttert und einer Queue die von den 1.000 Worker-Threads wieder mit den Ergebnissen an den Hauptthread am laufen gehabt.
Kleine, du hast genau keinen Plan von der Praxis. So ein Test besagt nichts.
Bonita.M schrieb:
Nein, das
assert
ist überhaupt nicht Quatsch.
Quatsch ist mMn. die Annahme dass der häufigste Fehlerfall bei SetEvent "zu wenig Resourcen" wäre. Ich wüsste nicht dass das überhaupt passieren kann. Wieso sollteSetEvent
irgendwelche Resourcen benötigen?Du spekulierst hier wild rum. Du weißt aber nicht was SetEvent im Kernel alles lostritt.
Und? Du genau so wenig. Im Gegensatz zu mir hast du aber Code geschrieben der sehr starke Annahmen darüber macht was mögliche Fehlerfälle bei
SetEvent
sein könnten.Bonita.M schrieb:
Real mögliche Fehlerfälle sind aber 1) das übergebene Handle ist ungültig und 2) das übergebene Handle nat nicht die nötigen Berechtigungen.
Kommt bei mir nicht vor.
Lol.
Du hast nichts verstanden.Danke und tschüss.
-
[quote]Natürlich ist es das, dafür hast du ja extra
m_dwRecursionCount
eingebaut. Verstehst du wirklich nicht was ich schreibe oder willst du mich bloss verarschen?[quote]Wenn auf eine Rekursion getoffen wird wird aber nich gelockt, sondern nur der Rekursionszähler erhöht
Ja, Mädchen. Ich versteh' dich schon. Du mich bloss nicht. Steig mal von deinem hohen Ross runter und lies Beiträge von anderen mal unter der Annahme dass sie vielleicht a) nicht blöd sind und b) Recht haben könnten.
Dashier geht mit deinem Code:Nein, Du verstehst meinen Code nicht.
Der US-Professor an den ich den geschickt habe hat den aber verstanden.cs.Enter(); cs.Enter(); cs.Wait(); cs.Leave(); cs.Leave();
Während des Wait() kann die CV dabei von anderen Threads gelockt werden. UND DAS IST EIN FEHLER!
Nein, kann nicht, weil beim wait Owners > waiters ist. Ist Owner - Waiters == 1 gibt es genau einen Thread der das Lock gelockt hat, ist es > 1, gibt es einen Thread der das Lock gelockt hat und zusätzlich Owners - Waiters Threads die auf das Entriegeln warten.
[quote="Bonita.M"]Und? Du genau so wenig. Im Gegensatz zu mir hast du aber Code geschrieben der sehr starke Annahmen darüber macht was mögliche Fehlerfälle bei
SetEvent
sein könnten.[quote]SetEvent gibt einen Fehlerode zurück, und ich gehe damit richtig um.
Du hast nichts verstanden.
Du hast nichts verstanden. Meintest Du bist in der Lage Locking-Primitive zu verstehen, kannst es aber offensichtlich nicht.
Wenn keiner den Speicherblock zerschießt in dem mein Lock liegt, dann haben wir es mit einem gültigen Handle zu tun - dann kann SetEvent nur noch aus anderen Gründen fehlschlagen, mglw. weil eben nicht genug Resourcen da sind um einen Thead der nun runnalble wird auf die Runnable-Liste zu packen. Für den Fehlerfall, dass jemand den Speicherblock zerschießt in dem das Handle liegt kann ich nichts.
-
Natürlich ist es das, dafür hast du ja extra
m_dwRecursionCount
eingebaut. Verstehst du wirklich nicht was ich schreibe oder willst du mich bloss verarschen?Wenn auf eine Rekursion getoffen wird wird aber nich gelockt, sondern nur der Rekursionszähler erhöht
Ja, Mädchen. Ich versteh' dich schon. Du mich bloss nicht. Steig mal von deinem hohen Ross runter und lies Beiträge von anderen mal unter der Annahme dass sie vielleicht a) nicht blöd sind und b) Recht haben könnten.
Dashier geht mit deinem Code:Nein, Du verstehst meinen Code nicht.
Der US-Professor an den ich den geschickt habe hat den aber verstanden.cs.Enter(); cs.Enter(); cs.Wait(); cs.Leave(); cs.Leave();
Während des Wait() kann die CV dabei von anderen Threads gelockt werden. UND DAS IST EIN FEHLER!
Nein, kann nicht, weil beim wait Owners > waiters ist. Ist Owner - Waiters == 1 gibt es genau einen Thread der das Lock gelockt hat, ist es > 1, gibt es einen Thread der das Lock gelockt hat und zusätzlich Owners - Waiters - 1 Threads die auf das Entriegeln warten. Zugegebenermaßen ist der Begriff Owner hier bissl verkehrt, da nur einer von Owner - Waiters tatsächlich das Lock gelockt hält.
Und? Du genau so wenig. Im Gegensatz zu mir hast du aber Code geschrieben der sehr starke Annahmen darüber macht was mögliche Fehlerfälle bei
SetEvent
sein könnten.SetEvent gibt einen Fehlerode zurück, und ich gehe damit richtig um.
Du hast nichts verstanden.
Du hast nichts verstanden. Meintest Du bist in der Lage Locking-Primitive zu verstehen, kannst es aber offensichtlich nicht.
Wenn keiner den Speicherblock zerschießt in dem mein Lock liegt, dann haben wir es mit einem gültigen Handle zu tun - dann kann SetEvent nur noch aus anderen Gründen fehlschlagen, mglw. weil eben nicht genug Resourcen da sind um einen Thead der nun runnable wird auf die Runnable-Liste zu packen. Für den Fehlerfall, dass jemand den Speicherblock zerschießt in dem das Handle liegt kann ich nichts.
-
löschen
-
Bonita.M schrieb:
Der US-Professor an den ich den geschickt habe hat den aber verstanden.
Das ist nicht beeindruckend. Ich hab den Thread nur überflogen und hab keine Ahnung, von dem eigentlichen Problem, aber ich möchte dich darauf hinweisen, dass Professoren normalerweise keinen besonders guten Ruf haben, bis auf wenige Ausnahmen. Außerdem können wir aus dem Kontext gerissen auch nicht wissen, ob er sich in das Problem überhaupt reingedacht hat oder ob ers nur überflogen hat. Dass er die Idee interessant fand, bedeutet nicht, dass er auch ausschließen kann, dass da Fehler oder potentielle Probleme sind.
-
Du hast immer noch nicht verstanden was ich dir sagen will.
Vielleicht hilft ein Beispiel. Klasse cv wie von dir verlinkt, folgender Test-Code:#include <cstdio> #include <cstdlib> #include <iostream> DWORD WINAPI ThreadFunc(LPVOID lpvThreadParam); CondVar cv; int main() { std::cout << "Locking...\n"; ::cv.Enter(); std::cout << "Locking again (recursive)...\n"; ::cv.Enter(); std::cout << "Starting thread...\n"; HANDLE th = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL); std::cout << "Waiting...\n"; ::cv.Wait(); std::cout << "We have been signaled.\n"; std::cout << "Unlocking...\n"; ::cv.Leave(); ::cv.Leave(); std::cout << "Bye.\n"; ::WaitForSingleObject(th, INFINITE); ::CloseHandle(th); } DWORD WINAPI ThreadFunc(LPVOID lpvThreadParam) { ::cv.Enter(); std::cout << "WE SHOULD NEVER GET HERE!\n"; ::cv.Release(); ::cv.Leave(); return 0; }
Das geht, darf aber nicht gehen.
Klar jetzt?SetEvent gibt einen Fehlerode zurück, und ich gehe damit richtig um.
Nein, tust du nicht. Ich habe dir auch beschrieben warum. Dass dir das egal ist, bzw. es dir wichtiger zu sein scheint dass du keinen Fehler zugeben musst, OK. Kann mir im Prinzip egal sein. Schreib halt weiter schlechten Code.
-
Ich hab dich schon verstanden. Im Gegensatz zum vor-vorangegangen Posting hast Du dich mal ausnahmsweise nicht mehrdeutig ausgedrückt.
Natürlich darf das gehen, mein Lock ist ja rekursiv. Wieso soll man auf eine doppelt gelockte CV nicht warten können?
Die inneren Lock- und Leave-Aufrufe machen mit dem Lock garnichts außer den Rekursionszähler zu erhöhen und wieder zu erniedrigen. Wait speichert diesen zwischen, und wenn es ein Signal emfpangen hat, restauriert es den wieder. Gelockt oder entlockt wird also durch die inneren Aufrufe nicht. Das ist absolut kein Bug, dass das geht, sondern so beabsichtigt.Wenn mein Unit-Test jetzt so aussähe ...
DWORD WINAPI ThreadFunc( LPVOID lpvThreadParam ); struct ThreadResult { DWORD dwThreadId; DWORD dwCounter; }; CondVar cv; list<ThreadResult> lstTR; bool volatile fStop = false; int main() { int const NTHREADS = 16; HANDLE ahThreads[NTHREADS]; int i; std::map<DWORD, DWORD> mTRs; for( i = 0; i < NTHREADS; i++ ) ahThreads[i] = CreateThread( NULL, 0, ThreadFunc, NULL, 0, NULL ); for( i = 0; i < 10000; i++ ) { ThreadResult tr; ::cv.Enter(); ::cv.Enter(); if( ::lstTR.empty() ) ::cv.Wait(); tr = ::lstTR.front(); ::lstTR.pop_front(); ::cv.Leave(); ::cv.Leave(); printf( "Thread: %08X - Number: %d\n", (unsigned)tr.dwThreadId, (unsigned)tr.dwCounter ); if( mTRs.find( tr.dwThreadId ) == mTRs.end() ) assert(tr.dwCounter == 0), mTRs[tr.dwThreadId] = tr.dwCounter; else assert((mTRs[tr.dwThreadId] + 1) == tr.dwCounter), mTRs[tr.dwThreadId] = tr.dwCounter; } for( ::fStop = true, i = 0; i < NTHREADS; i++ ) WaitForSingleObject( ahThreads[i], INFINITE ); return 0; } DWORD WINAPI ThreadFunc( LPVOID lpvThreadParam ) { ThreadResult tr; tr.dwThreadId = GetCurrentThreadId(); tr.dwCounter = 0; for( ; !::fStop; tr.dwCounter++ ) { ::cv.Enter(); ::cv.Enter(); ::lstTR.push_back( tr ); ::cv.Release(); ::cv.Leave(); ::cv.Leave(); Sleep( 10 ); } return 0; }
...dann ist das von der Funktionsweise so als würden die inneren Locks und Leaves nicht exisitieren. Der Code läuft genau so wie gewollt durch.
Und die Endlosschleife bei SetEvent ist kein schlecher Code - das geht nicht anders weil die CV so simpel gestrickt ist. Das assert ist eigentlich überflüssig.
-
Achherrjeh, Bonita, ich weiss was rekursive Mutexen sind und wie sie funktionieren. Ich weiss auch was du dir dabei gedacht hast. Ich versuche dir nur zu erklären dass es trotzdem unsinnig ist. Es maskiert gefährliche Anwendungsfehler.
Wenn du es mir nicht glaubst, dann guck doch mal ob du eine Mutex/CV Implementierung findest die so arbeitet. Ich kenne keine. Und das hat schon seinen Grund.
Bonita.M schrieb:
Und die Endlosschleife bei SetEvent ist kein schlecher Code - das geht nicht anders weil die CV so simpel gestrickt ist. Das assert ist eigentlich überflüssig.
mimimi
Ne, ich erklärs dir jetzt nicht nochmal.
-
hustbaer schrieb:
Achherrjeh, Bonita, ich weiss was rekursive Mutexen sind und wie sie funktionieren. Ich weiss auch was du dir dabei gedacht hast. Ich versuche dir nur zu erklären dass es trotzdem unsinnig ist. Es maskiert gefährliche Anwendungsfehler.
Das doppelte Locken und darin das Wait mag in der Praxis kaum vorkommen, aber es ist kein Anwendungsfehler. Ich finde es nicht falsch diesen seltenen Fall mit zu unterstützen.
Hättest Du dich direkt von Anfang an vollständig und nicht mehrdeutig ausgedrückt, dann hätte ich deine seltsamen Bedenken gleich verstanden. Das hast Du aber nicht.
-
Es ist sehr oft ein Anwendungsfehler. Und wenn es keiner ist, dann ist das rekursive Locken vermeidbar. Es gibt also keinen Grund Wait einen rekursiven Unlock machen zu lassen. Es gäbe dagegen gute Gründe in Wait ein assert() einzubauen um abzusichern dass der Fall eben nicht auftritt.
Aber du weisst ja alles besser.
-
Bonita.M schrieb:
Hättest Du dich direkt von Anfang an vollständig und nicht mehrdeutig ausgedrückt, dann hätte ich deine seltsamen Bedenken gleich verstanden. Das hast Du aber nicht.
Ja, klar, liegt bestimmt an mir.
Muss so sein. Du machst ja keine Fehler. Und verstehst auch alles.
-
hustbaer schrieb:
Es ist sehr oft ein Anwendungsfehler. Und wenn es keiner ist, dann ist das rekursive Locken vermeidbar. Es gibt also keinen Grund Wait einen rekursiven Unlock machen zu lassen. Es gäbe dagegen gute Gründe in Wait ein assert() einzubauen um abzusichern dass der Fall eben nicht auftritt.
Man kann nicht 100%ig ausschließen, dass jemand sowas absichtlich macht und der Code korrekt ist. Daher ist ein assert() hier falsch.
hustbaer schrieb:
Ja, klar, liegt bestimmt an mir.
Muss so sein. Du machst ja keine Fehler. Und verstehst auch alles.Ja, das liegt an dir. Z.B. sprachst Du vom doppelten Locken, wobei nicht klar war ob Du damit ein verschachteltes Locken meinst oder ein Locken in zwei Threads. Das ist nicht die einzige Uneindeutigkeit mit der Du kommst. Du vervollständigst deine Aussagen nach und nach, und kommst nicht direkt von Anfang an mit Klarheit.
-
Bonita.M schrieb:
löschen
Zuletzt bearbeitet von Bonita.M am 14:45:49 27.05.2016, insgesamt 2-mal bearbeitet
Bonita.M schrieb:
Zuletzt bearbeitet von Bonita.M am 18:11:11 27.05.2016, insgesamt 10-mal bearbeitet
Bonita.M schrieb:
Zuletzt bearbeitet von Bonita.M am 18:23:06 27.05.2016, insgesamt 3-mal bearbeitet
Ich kommentiere das jetzt mal nicht.
-
Win10BugFinderLober schrieb:
Ich kommentiere das jetzt mal nicht.
Wäre besser wenn mein Vorredner auch mal die Editierfunktion genutzt hätte und sich klar ausgedrückt hätte.
-
Bonita.M schrieb:
hustbaer schrieb:
Es ist sehr oft ein Anwendungsfehler. Und wenn es keiner ist, dann ist das rekursive Locken vermeidbar. Es gibt also keinen Grund Wait einen rekursiven Unlock machen zu lassen. Es gäbe dagegen gute Gründe in Wait ein assert() einzubauen um abzusichern dass der Fall eben nicht auftritt.
Man kann nicht 100%ig ausschließen, dass jemand sowas absichtlich macht und der Code korrekt ist. Daher ist ein assert() hier falsch.
Außerdem: das mit dem doppelten Locken und dann warten geht mit der Condvar von Win32 auch. Ich habe eine testweise Ersatzklasse für meine, die die CondVar von Win32 nutzt. Da funktioniert das auch.Also du erlaubst lieber etwas was sonst keine Implementierung erlaubt, und was sehr oft ein Anwendungsfehler ist... als ein assert einzubauen das dem User sagt dass er vermutlich 'was falsch macht.
Sehr intelligent.
Genau das meinte ich mithustbaer schrieb:
ps: Natürlich ist das dein Code, und du kannst definieren was du willst. Du kannst also auch definieren dass dein cv::Wait dieses verhalten hat. Dann ist es kein Fehler. Dann ist nur deine cv Klasse ein nutzloses Teil von dem man besser die Finger lassen sollte.
Bonita.M schrieb:
Ja, das liegt an dir. Z.B. sprachst Du vom doppelten Locken, wobei nicht klar war ob Du damit ein verschachteltes Locken meinst oder ein Locken in zwei Threads. Das ist nicht die einzige Uneindeutigkeit mit der Du kommst. Du vervollständigst deine Aussagen nach und nach, und kommst nicht direkt von Anfang an mit Klarheit.
Ich habe z.B. geschreiben "Wait aufzurufen während man die Mutex doppelt gelockt hat ist ein Anwendungsfehler. "
Wie sollen bitte zwei Threads die Mutex gleichzeitig gelockt haben? Damit kann nur gemeint sein rekursiv im selben Thread.
Oder auchhustbaer schrieb:
Den Fall dass Wait mit dwSavedRecusionCount > 1 aufgerufen wird solltest du einfach nur mit assert() verbieten bzw. ggf. abort() aufrufen. Die Mutex einfach so aufzumachen ist mMn. einfach nur falsch. Grob falsch. Gefährlich falsch.
Mal abgesehen davon dass ich hier besser
m_dwRecursionCount
stattdwSavedRecusionCount
schreiben hätte sollen... was ist daran bitte unklar?Du musst bloss lesen lernen.
-
hustbaer schrieb:
Ich habe z.B. geschreiben "Wait aufzurufen während man die Mutex doppelt gelockt hat ist ein Anwendungsfehler. "
Doppelt gelockt könnte ja auch zweimal aus zwei Threads Enter aufgerufen zu haben bedeuten, und nicht zweimal gleichzeigig erfolgreich gelockt.
hustbaer schrieb:
Den Fall dass Wait mit dwSavedRecusionCount > 1 aufgerufen wird solltest du einfach nur mit assert() verbieten bzw. ggf. abort() aufrufen. Die Mutex einfach so aufzumachen ist mMn. einfach nur falsch. Grob falsch. Gefährlich falsch.
Daran ist garnichts gefährlich. Wenn die CV richtig gehandhabt wird ist das funktionierender Code. Und da sowas in der Praxis eh nicht vorkommt ist das eigentlich egal.
-
lol
Tu was du willst. Glaub was du willst.
Ich hab hier schon viel zu viel Zeit verschwendet.
-
Ein quengeliges, egozentrisches und von sich selbst übermäßig überzeugtes Weib - der Grund wieso ich mich von meiner letzten Frau getrennt habe.
EDIT:
6 mal editiert nur weil ich nicht wusste wie man "quengelig" richtig schreibt.EDIT#2:
http://www.duden.de/rechtschreibung/quengeln#b2-Bedeutung-1
-
Ich denke nicht dass das jetzt 'was zur Sache tut.
-
hustbaer schrieb:
Ich denke nicht dass das jetzt 'was zur Sache tut.
Hat zugegebenerweise nur bedingt was mit der Sache zu tun. Nur weil mich die Verhaltensweise dieser lieblichen Bonita aber an gewisse Verhaltensweisen erinnert hat. Man darf ja wohl auch manchmal etwas abschweifen. Oder nicht?