Thread problem



  • Bist du dir sicher, dass du nicht irgendwo doch eine Kopie von deinem Singleton erzeugst? Verbiete mal explizit den Copy-Construktor & Zuweisungs-Operator, indem du sie private machst...



  • das bind kopiert ??? Kann das sein ??? Moment mal..



  • AlexanderKiebler schrieb:

    das bind kopiert ??? Kann das sein ??? Moment mal..

    Das bind kopiert das Objekt nicht, wenn du einen Zeiger übergibst... Also es kopiert nur den Zeiger, nicht aber das Objekt, auf das verwiesen wird.
    Wenn du das this dereferenzierst, dann würde eine Kopie erzeugt...

    EDIT: http://www.boost.org/doc/libs/1_47_0/libs/bind/bind.html#with_member_pointers



  • Okay,
    ich habs denke ich ganz gut hin bekommen.
    THX für die Hilfe.

    jetzt ist es aber so, dass ich für ein boost::mutex auf dem Heap einen
    fehler beim bauen bekomme.

    Er sagt mir dass boost::_noncopyable privat sei.... ????

    Das hilft ir gerade aber nicht wirklich weiter.

    Also einfach ein

    boost::mutex mutex;
    

    und schon habe ich die Fehlermeldung



  • Also ich vermute mal, dass dein mutex eine Member-Variable in einer deiner Klassen ist(?)... Im Default-Copy-Constructor dieser Klasse möchte er dann alle Member kopieren, was er aber nicht kann, da ein mutex nicht kopierbar ist. Folglich wirst du irgendwo in deinem Code eine Kopie dieses Objektes erzeugen, das den Mutex enthält, da sonst (glaub ich) keine Fehlermeldung kommen sollte.

    Naja... Ist zwar ziemlich spekulativ, aber evtl. stimmts...



  • Oka,
    so läuft =).

    Ich hatte aber noch das Problem dass ich bei Folgemdem singelton
    zweimal den destruktoraufruf hatte:

    ...
    public:
        static DataBase & getInstance(){
            static DataBase instance;
            return instance;
        }
        ~DataBase();
    private:
        DataBase(){}
    ...
    

    Also ~DataBase wird zweimal aufgerufen, DataBase nur einmal.



  • Ergänz mal Folgendes und du kriegst vermutlich einen Compiler-Fehler.

    private:
            DataBase(const DataBase&){}
    

    Kurz gesagt, du erzeugst noch irgendwo eine Kopie...
    Es wir vermutlich einmal der parameterlose Konstruktor aufgerufen und einmal
    der Copy-Constructor, den du hiermit verbietest.



  • HI XSpille,

    ich weiß, es Nervt, aber ich bin zum alten Problem zurückgekehrt =)... sorry.
    Hab jetzt sowas in der Art gemacht:

    class FU{
    
    FU(){
    
    FU_Worker_Thread=new boost::thread(boost::bind(&FU_Worker::_Progress_FU_Worker,boost::ref(FW)));
    }
    
    _stop(){*(FW.FU_Worker_Thread_run)=false;};
    ...
            class FU_Worker
            {
                public:
                    FU_Worker(){FU_Worker_Thread_run = new bool;*FU_Worker_Thread_run=true;}
                    ~FU_Worker(){/// Aufräumen}
    
                    /// Das ist der Thread
                    void _Progress_FU_Worker()
                    {
                        while(*FU_Worker_Thread_run)
                        {
                          /// Mach was tolles
                        }
                    }
    
                    bool* FU_Worker_Thread_run;
    
            };
    
            FU_Worker FW;
            boost::thread* FU_Worker_Thread;
    
    };
    

    Das Problem ist, wenn ich die boolsche variable
    nicht als Pointer mache, dann habe ich in FU und in FU_Worker zwei verschiedene
    boolsche variablen. Also ich habe unterschiedliche Addressen.
    Ich hatte erwartet, dass er wegen den boost::ref(FW) im Bind
    nicht kopiert. ??? Irgendwas hab ich da nicht verstanden.
    Mit dem Pointer gehts einwandfrei, aber ich würder gerne ohne Pointer auskommen.
    Also in der FU_Worker klasse.



  • kein Thema...

    Wenn du keinen Mutex verwendest, sollte die Variable volatile sein um zu garantieren, dass der alte Wert im anderen Thread nicht gecached ist.

    Lass mal folgendes kompilerierfähiges(!!! 🙂 ) Programm laufen:

    #include <iostream>
    #include <boost/thread.hpp>
    #include <boost/ref.hpp>
    
    class FU : private boost::noncopyable{ 
    public:
    	FU() /*: FW()*/{ 
    
    		FU_Worker_Thread=new boost::thread(boost::bind(&FU_Worker::_Progress_FU_Worker,boost::ref(FW))); 
    	} 
    
    	class FU_Worker : private boost::noncopyable
    	{
    	private:
    		FU_Worker(const FU_Worker&){}
    	public: 
    		FU_Worker(){FU_Worker_Thread_run=true;} 
    		~FU_Worker(){} 
    
    		/// Das ist der Thread 
    		void _Progress_FU_Worker() 
    		{ 
    			while(true) 
    			{
    				if(FU_Worker_Thread_run)
    					std::cout << "Worker thread " << "yes " << this << std::endl;
    				else
    					std::cout << "Worker thread " << "no " << this << std::endl;
    			} 
    		} 
    
    		volatile bool FU_Worker_Thread_run; 
    	}; 
    
    	FU_Worker FW; 
    	boost::thread* FU_Worker_Thread; 
    
    	void toggle(){
    		if(FW.FU_Worker_Thread_run){
    			std::cout << "main thread " << "yes -> no" << &(this->FW) << std::endl;
    			FW.FU_Worker_Thread_run = false;
    		}
    		else{
    			std::cout << "main thread " << "no -> yes" << &(this->FW) << std::endl;
    			FW.FU_Worker_Thread_run = true;
    		}
    	}; 
    
    };
    
    int main(){
    	FU* fu = new FU();
    	while(true) 
    	{ 
    		fu->toggle();
    	} 
    }
    

    Ändern sich bei dir die Werte im Worker-Thread?
    Also es bei mir sieht es ziemlich durcheinander aus wegen der Kontextwechsel, aber die Werte im Worker verändern sich.

    Wenn ja, poste mal ein kompilierfähiges Programm, das bei dir nicht funktioniert.

    Also die Memory-Leaks müssen natürlich noch raus...
    Wo ist eigentlich der Singleton hin? ^^



  • XSpille schrieb:

    .

    Wenn du keinen Mutex verwendest, sollte die Variable volatile sein um zu garantieren, dass der alte Wert im anderen Thread nicht gecached ist.

    volatile hat mit Threads nichts zu tun. Microsoft unterstützt dies mittlerweile, weil der Irrglaube so verbreitet ist, aber portabel ist es nicht.



  • Hi,

    der singelton ist in der Vereinfachung verschwunden =)...
    Schaus mir gerade mal durch.

    Volatile habe ich eigentlisch schonmal versucht. ...
    In C# geht das, aber bei C++ hab ich eigentlich nie nen Unterschied feststellen könne.
    Werds nochmal versuchen.

    Ich möchte das ganze später einfach in ne DLL / so packen.
    Und da brauch ich ne Factory function, und die Instanzen kommen im meinen
    Einfachton =)....

    So werd mal schauen was er bei mir so sagt.
    Welche Compiler hast du ??
    Ich hab i686-pc-linux-gnu-4.4.5

    EDIT: Ich mutexe schon, aber mich interessiert ja wiso dei boolsche variable zwei unterschiedliche Addressen hat, wenn ich sie auf dem stack anlege.



  • manni66 schrieb:

    XSpille schrieb:

    .

    Wenn du keinen Mutex verwendest, sollte die Variable volatile sein um zu garantieren, dass der alte Wert im anderen Thread nicht gecached ist.

    volatile hat mit Threads nichts zu tun. Microsoft unterstützt dies mittlerweile, weil der Irrglaube so verbreitet ist, aber portabel ist es nicht.

    Danke für die Info...
    Aber volatile garantiert doch, dass das Caching der Variable verhindert wird, oder? Und genau das muss/sollte doch in diesem Fall gewährleistet sein, oder?

    Wikipedia sagt: http://de.wikipedia.org/wiki/Volatile_(Informatik)

    In C und C++ wird durch diesen Typqualifikator spezifiziert, dass sich der Wert der Variablen außerhalb des aktuellen Programmkontextes ändern kann

    Und ein anderer Thread ist doch ein Verändern außerhalb des aktuellen Programmkontest, oder?

    (Ich bin jetzt einfach naiv davon ausgegangen, dass diese Info bei Wikipedia korrekt ist 🙄 )



  • AlexanderKiebler schrieb:

    Welche Compiler hast du ??

    Ich verwende Mac OS X:
    g++ (GCC) 4.6.1 20110325 (prerelease)



  • Genau die überlegung ist bei mir auch angestanden.
    Ne zuweisung verhindern, damit der Wert abgefragt wird.

    Bei mir gehts gerade sowohl mit, als auch ohne volatile.

    EDIT: Soweit ich weiß sind die Compiler mit boost noch nicht getestet oder ??



  • XSpille schrieb:

    Und ein anderer Thread ist doch ein Verändern außerhalb des aktuellen Programmkontest, oder?

    Nein, C++ wird erst im kommenden Standard C++11 Threads kennen, daher bezieht sich das auf Signalhandler u.ä.. Der englische Wikieintrag ist da viel ausführlicher.

    Hier wird volatile eigentlich ganz gut beschrieben: http://drdobbs.com/high-performance-computing/212701484.
    Auch die vielen anderen Artikel von Herb Sutter zur Threadthematik sind lesenswert.



  • XSpille schrieb:

    Aber volatile garantiert doch, dass das Caching der Variable verhindert wird, oder?

    Ja, das schon.

    Und genau das muss/sollte doch in diesem Fall gewährleistet sein, oder?

    Das ist notwendig, aber nicht ausreichend.
    Es fehlt nämlich noch irgendwer, der dir eine Garantie über das Speichermodell im Zusammenhang mit Multithreading gibt.
    Und das tut der C++ (03) Standard nicht.

    Konkret kann das heissen: es könnten Memory-Barriers nötig sein, um die Sichtbarkeit von Änderungen zu garantieren. Und es kann sein, dass Reads und/oder Writes der Variable nicht Atomic sind. Das wäre u.U. auch doof.
    Uswusf.

    Multithreading ist vom C++ 03 Standard einfach nicht abgedeckt, und daher kann volatile auch keine allgemein gültige Verwendung im Zusammenhang mit Threads haben.

    ----

    MSVC garantiert dass volatile das tut, was es auch in Java oder C# tut. Andere Compiler garantieren das nicht.



  • hustbaer schrieb:

    MSVC garantiert dass volatile das tut, was es auch in Java oder C# tut. Andere Compiler garantieren das nicht.

    Heißt, in MSVC ist bei einer volatilen Variable keine Synchronisation durch Mutexes o.ä. mehr erforderlich (So ist es doch in Java, oder?) ?



  • manni66 schrieb:

    volatile hat mit Threads nichts zu tun. Microsoft unterstützt dies mittlerweile, weil der Irrglaube so verbreitet ist, aber portabel ist es nicht.

    Microsoft unterstützt es, weil es praktisch ist ein definiertes Speichermodell zu haben.



  • 314159265358979 schrieb:

    hustbaer schrieb:

    MSVC garantiert dass volatile das tut, was es auch in Java oder C# tut. Andere Compiler garantieren das nicht.

    Heißt, in MSVC ist bei einer volatilen Variable keine Synchronisation durch Mutexes o.ä. mehr erforderlich (So ist es doch in Java, oder?) ?

    Ab MSVC 2005 haben Lesezugriffe mit volatile "acquire" Semantik, und Schreibzugriffe "release" Semantik.

    http://msdn.microsoft.com/en-us/library/12a04hfd(v=vs.80).aspx

    Auf x86 und x64 Plattformen sind (unabhängig vom Compiler) Zugriffe auf Variablen mit bis zu 8 Byte "atomic", wenn die Adresse passend aligned ist (=die Variable muss vollständig innerhalb einer Cache-Line liegen), WENN der Zugriff mit einer einzigen Instruction passiert.

    MSVC erzeugt passenden Code (Quelle kann ich dir aber keinen nennen), d.h. mit MSVC sind solche Zugriffe dann "atomic" UND "acquire" bzw. "release".

    Und wenn man an den Defaults nichts ändert, tut man sich auch ziemlich schwer, Variablen zu erzeugen die nicht passend aligned wären.

    D.h. mit MSVC kann man "double checked locking" korrekt implementieren, Spin-Locks mit einem einfachen "m_lock_var = 0" freigeben etc.



  • Danke euch für die Ausführungen zu volatile...

    Inzwischen erinnere ich mich sogar, es gewusst zu haben 🤡


Anmelden zum Antworten