delete [] thread-safe machen



  • Hallo zusammen,

    warum reicht es nicht aus, wenn ich jeden Aufruf von delete [] durch ein Mutex schütze? Was ist noch zu beachten?

    Danke für Eure Antworten!



  • Ich versteh nicht ganz, warum solltest du jeden Aufruf von delete[] durch ein Mutex "schützen"? Bist du dir sicher dass du den Sinn von einem Mutex verstanden hast?



  • Die "default"-Implementierung von delete[] ist doch threadsafe, oder?



  • Ja.



  • Denn Sinn eines Mutex kenne ich denke ich. Es dient dazu, gleichzeitigen Zugriff auf begrentzte Resourcen zu unterbinden bzw. exklusiv zu gewähren.

    Was ich allerdings mit dem Mutex bei delete [] zu erreichen versuche weiss ich auch nicht ganz.

    Das Problem ist, dass meine Threads auf dem Heap Speicher allokieren und diesen auch wieder freigeben.

    Beim Freigeben knallt es dann aber. Das mit dem Mutex war ein Schnellschuß, das Problem zu lösen.

    Was kann ich tun?



  • curry-king schrieb:

    Was kann ich tun?

    Rausfinden warum es knallt.

    Kann es sein dass eben einfach mehrere Treads versuchen das selbe Array zu deleten[]? Wenn ja, dann hilft natürlich kein Mutex um delete[] herum, weil ob die Threads das Array nun alle parallel deleten oder schön der Reihe nach ändert nix dran, dass das Array am Ende zu oft deleted wird...



  • Schon mal den Debugger angeworfen? Double-Delete? Delete auf Speicher, der dir nicht gehört? Das kann viele Gründe haben.
    Allerdings solltest du new[] und delete[] ohnehin nicht verwenden, denn dafür gibt es std::vector.



  • dot schrieb:

    curry-king schrieb:

    Was kann ich tun?

    Rausfinden warum es knallt.

    Like it

    314159265358979 schrieb:

    Allerdings solltest du new[] und delete[] ohnehin nicht verwenden, denn dafür gibt es std::vector.

    Ich arbeite mit 3000 Zeilen Code vom Vorgänger die voll von new[] und delete[] sind...

    Ich werde den Debugger mal Fragen!



  • Dann würde ich den Code an deiner Stelle neu schreiben.



  • curry-king schrieb:

    Ich arbeite mit 3000 Zeilen Code vom Vorgänger

    Dass jemand anderes den Code geschrieben hat ist kein Grund, von einem nötigen Refactoring abzusehen 😉



  • pumuckl schrieb:

    curry-king schrieb:

    Ich arbeite mit 3000 Zeilen Code vom Vorgänger

    Dass jemand anderes den Code geschrieben hat ist kein Grund, von einem nötigen Refactoring abzusehen 😉

    Denke ich auch. 3000 Zeilen sind in einer Stunde durch, da lohnt das Ärgern doch nicht.



  • 3000 Zeilen in einer Stunde refactorn ist ne hübsch naive Vorstellung.
    Das müssen schon recht zivilisierte 3000 Zeilen sein dass sich das ausgeht.
    Erstmal muss man verstehen was überhaupt abgeht, dann kann man es geradebiegen. Im Idealfall kann man sich Stück für Stück ansehen, Stück für Stück verstehen und dann umbauen, und am Ende hat man ein Programm das funktioniert. Und selbst das kann länger dauern als ne Stunde.



  • wenn der Code gut mit Unit Tests abgedeckt ist, sollte das Refactoring recht schnell gehen. Wenn diese aber nur unvollständig oder gar nciht vorhanden sind, dann wird es unangenehm...



  • Auch das ist Wunschdenken.
    Kein nicht-trivialer Code ist soweit mit Unit-Tests abgesichert, dass diese 100% aller möglichen Fälle abdecken. Meist nichtmal 100% aller relevanten Fälle.

    OK, man *kann* dann flott refactorn, nur kann man eben nicht sicher sein dass nachher auch wirklich alles passt, nur weil die Tests durchlaufen. Fehlerbehandlung ist z.B. etwas, was in kaum einem Projekt auch nur annähernd brauchbar von automatischen Tests abgedeckt ist.



  • cooky451 schrieb:

    Denke ich auch. 3000 Zeilen sind in einer Stunde durch, da lohnt das Ärgern doch nicht.

    Du hast noch keinen wirklich üblen Code übernehmen müssen. 3000 Zeilen können ausreichen, um einen Tage- oder Wochenlang zu beschäftigen. Neu schreiben ist manchmal auch nicht drin. Z.B. wenn dieser Code mit Hardware kommuniziert, aber nichts, nicht mal das Protokoll, dokumentiert ist. So einen haufen Müll zu verstehen dauert sehr lange. Und teilweise ist das alles noch so fragil, dass jede Änderung Adrenalinschübe verursacht.

    Willkommen in der realen Welt



  • Und selbst bei wirklich guten Code* führt man keine größeren Änderungen in einer Stunde durch. Du hast Vorstellunge...

    *Was der Notwendigkeit nach Überarbeitung natürlich widerspricht.



  • Bei über 3000 Zeilen von folgendem Code würde das refactoring dann wahrscheinlich ein MJ dauern :-)...
    Mein Problem ist gelöst, ich hatte mehr freigegeben als ich allokiert hatte!

    int update_table2(vector<string> staterows, vector<string> transrows, vector<string> columns,bool*** table, string stream, size_t old_states, size_t old_trans, size_t old_columns)
    {
    	bool **new_table;
    
    	(new_table) = new bool* [(columns).size()];
    	for(unsigned int iu=0;iu<(columns).size();iu++) (new_table)[iu] = new bool[(staterows).size()+(transrows).size()];
    
    	string newquerry("");
    	for(unsigned int iu=0;iu<(staterows).size()+(transrows).size();iu++)
    	{
    		for(unsigned int ju=0;ju<(columns).size();ju++)
    		{	
    			if((iu<old_states)&&(ju<old_columns-1)) { // copy old states
    			new_table[ju][iu] = (*table)[ju][iu]; 
    			}
    			else{
    				if((iu>staterows.size()-1)&&(ju<old_columns-1)&&(iu<staterows.size()+old_trans)){ //copy old transitions
    					new_table[ju][iu] = (*table)[ju][iu-staterows.size()+old_states]; 
    				}
    				else{
    					newquerry = (iu>(staterows).size()-1)? (transrows)[iu-(staterows).size()] : (staterows)[iu];
    					newquerry += (columns)[ju];
    					(new_table)[ju][iu]=querry(newquerry,stream); //transitions
    				}
    			}
    		}
    	}
    
    	// copy new_table into table
    	delete [] (*table);
    	(*table) = new bool* [(columns).size()];
    	for(unsigned int iu=0;iu<(columns).size();iu++) (*table)[iu] = new bool[(staterows).size()+(transrows).size()];
    	for(unsigned int iu=0;iu<(staterows).size()+(transrows).size();iu++)
    	{
    		for(unsigned int ju=0;ju<(columns).size();ju++)
    		{	
    			(*table)[ju][iu]=new_table[ju][iu]; //copy
    		}
    	}
    
    	delete [] new_table;
    	return 0;
    }
    
    bool fix_closed(vector<string> *staterows, vector<string> *transrows, vector<string> *columns, vector<string>alpha, bool ***table,string stream)
    {
    	size_t old_state = (*staterows).size();
    	size_t old_trans = (*transrows).size();
    	size_t old_col = (*columns).size();
    
    	bool found;
    	string transition;
    	string help;
    	for(unsigned int i=0;i<(*transrows).size();i++)
    	{
    		for(unsigned int j=0;j<(*staterows).size();j++)
    		{
    			found = true;
    			for(unsigned int k=0;k<(*columns).size();k++)
    			{
    				if ((*table)[k][j] != (*table)[k][i+(*staterows).size()]) {found = false; break;}
    			}
    			if(found) break;
    		}
    		if (!found)
    		{// fix transrow 
    			transition = (*transrows)[i];
    			(*staterows.......................................
    


  • cooky451 schrieb:

    3000 Zeilen sind in einer Stunde durch, da lohnt das Ärgern doch nicht.

    Respekt 😉
    Erfassen, verstehen und eventuell korrigieren einer Zeile in 1,2 Sekunden.



  • Shiba schrieb:

    Respekt 😉
    Erfassen, verstehen und eventuell korrigieren einer Zeile in 1,2 Sekunden.

    Naja, es ist ja nicht jede Zeile betroffen. Eine Stunde ist natürlich dennoch viel zu wenig.

    Aber bei dem geposteten Code ist dennoch durch minimale Änderungen einiges zu verbessern. Bspw. die Übergabe als Wert und damit das notwendige Kopieren könnte mit konstanten Referenzen leicht umgangen werden, ohne den Code zu ändern.
    Und auch sonst wäre in diesem Beispiel wahrscheinlich der Einsatz von Pointer-Containern die bessere Wahl...


  • Mod

    Hier lässt sich sogar ohne stilistische Änderungen einiges verbessern.
    Wer löscht eigentlich die alten bool-Arrays? Ich vermisse da ein delete[].
    Kann nat. auch an anderer Stelle des Programmes stehen... in diesem Fall wäre es allerdings diese geteilte Zuständigkeit, um die ich mich zuerst kümmern würde.


Log in to reply