Datenaustausch zwischen thread?



  • Hallo Leute,

    ich will Daten von ein Thread zum UI Thread schicken .
    Laut google ist das die üblich Vorgehensweise: (pseudo)

    Senden: (Thread)

    #define MY_MESSAGE (WM_APP + 1)
    mydata* pdata = new mydata; // alloc
    ::PostThreadMessage(hThread, WM_MESSAGE, pdata, 0);
    

    Empfange: (UI THreadI)

    ON_MESSAGE( MY_MESSAGE , OnMyMessage )
    
    LRESULT OnMyMessage (WPARAM wParam, LPARAM lParam)
    {
        mydata* pdata = (mydata*) wParam;
       ...
       delete pdata; // free
    }
    

    Is das ne saubere Vorgehensweiße?



  • @SoIntMan
    Würd ich so nicht machen. Ist dein Thread eine Klasse? Wo hält er die Daten, die er bereitstellen soll? Ich habe sowas bisher immer so gelöst:

    //
    // Producer
    //
    class MyThread
    {
       ...
       SomeData Data_;
       mutable CriticalSection CS_;
    
    private:
       void set_data( SomeData const& data )
       {
          ScopedCSLock lock( CS_ );
          Data_ = data;
       }   
    
    public:
       SomeData data() const
       {
          ScopedCSLock lock( CS_ );
          return Data_;
       }
    
       void CalcResult()
       {
          SomeData local = ...;
          DoSomething();  
          NotifyListeners(); // Hier passiert WM_USER 
    };
    
    
    //
    // Consumer
    //
    class MyWindow 
    {
       void OnDataChanged( MyThread const& thread )
       {
          SomeData local = thread.data();
          // mach was damit
       }
    };
    

    In Multithreading-Umgebungen arbeite ich fast nur noch mit Kopien, außer die Datenstrukturen sind wirklich groß und teuer zu kopieren. Das hat den Vorteil, dass ich keine data races mehr habe, weil jeder Thread mit seiner eigenen Kopie arbeitet.

    Edit:
    Vorgehensweise



  • @DocShoe sagte in Datenaustausch zwischen thread?:

    Würd ich so nicht machen. Ist dein Thread eine Klasse?

    Ja ist ein CWnd (MFC) Fenster:, darin erzeuge ich ein thread ::CreateThread .. und will eben daten austauschen.

    Ich könnte eine variable anlegen und mit mutex/cs safe machen... oder eine queue dazwischen ...

    ich befinde mich in der c++03 welt.. 🙂



  • @SoIntMan
    Macht ja nix, mit der MFC ist es in diesem Fall ja noch einfacher, weil du dir deinen ScopedCSLock um eine CCriticalSection bauen kannst.



  • @DocShoe sagte in Datenaustausch zwischen thread?:

    Macht ja nix, mit der MFC ist es in diesem Fall ja noch einfacher, weil du dir deinen ScopedCSLock um eine CCriticalSection bauen kannst.

    optimal, dann probiere es damit aus:) Ich danke dir



  • Was eine gute Möglichkeit ist, kommt drauf an was du machen willst. Daten übergeben, klar, aber welche Daten für welchen Zweck übergeben usw.

    Es gibt schon Fälle wo PostThreadMessage Sinn macht und vielleicht sogar einfacher zu verwenden ist als shared memory mit Locks (CCriticalSection oder was auch immer).

    Gibt aber auch Fälle wo die Variante mit shared memory und Locks besser ist. Kommt halt eben drauf an 🙂



  • @hustbaer sagte in Datenaustausch zwischen thread?:

    Es gibt schon Fälle wo PostThreadMessage Sinn macht und vielleicht sogar einfacher zu verwenden ist als shared memory mit Locks (CCriticalSection oder was auch immer).

    Das Problem ist, wenn ich nur ein ptr übergebe und im handler wieder freigebe, dass ich ein memory leak bekommen wenn ich die anwendung schließe, da wohl die message queue der ui beenden wird, before alles message bearbeitet wurden und so ein delete aufällt



  • Naja, das ist nicht wirklich ein Problem. Der Speicher wird ja freigegeben wenn das OS den Prozess entfernt.



  • @hustbaer sagte in Datenaustausch zwischen thread?:

    Naja, das ist nicht wirklich ein Problem. Der Speicher wird ja freigegeben wenn das OS den Prozess entfernt.

    ja aber er gibt in der VS console beim schliesen ein memory block an der nich freigeben wurde



  • @hustbaer sagte in Datenaustausch zwischen thread?:

    Naja, das ist nicht wirklich ein Problem. Der Speicher wird ja freigegeben wenn das OS den Prozess entfernt.

    Aber aus Entwicklersicht finde ich das dennoch irgendwie "unbefriedigend".





  • @Quiche-Lorraine sagte in Datenaustausch zwischen thread?:

    @It0101
    Raymond Chen denkt darüber etwas anders:

    When DLL_PROCESS_DETACH tells you that the process is exiting, your best bet is just to return without doing anything

    1. Muss man den kennen? 😃
    2. Mir gehts hauptsächlich darum: Ein Experte weiß genau, wo er die Zügel etwas lockerer lassen kann. Weniger erfahrene können das nicht. Ich will nur vermeiden, dass von solchen Aussagen ein falsches Signal ausgesandt wird.


  • @SoIntMan sagte in Datenaustausch zwischen thread?:

    @hustbaer sagte in Datenaustausch zwischen thread?:

    Naja, das ist nicht wirklich ein Problem. Der Speicher wird ja freigegeben wenn das OS den Prozess entfernt.

    ja aber er gibt in der VS console beim schliesen ein memory block an der nich freigeben wurde

    Stimmt. Und da sollte man nicht anfangen das zu ignorieren, weil man sonst echte Leaks nicht mehr findet.

    Egal. Shared memory Multithreading hat auch so seine Probleme. Ich bleibe dabei: es kommt drauf an was besser ist, und es gibt Fälle wo Kommunkation mittels Window-Messages das Mittel der Wahl ist. Probleme mit nicht freigegebenen "Kommunikationspuffern" kann man auch vermeiden indem man nur eine "es gibt was zum Updaten" Message schickt, und die neuen Daten in eine Membervariable steckt. Zugriff synchronisiert über eine Mutex. Ala

    void Foo::threadFn() {
        while (true) {
            SomeData data = computeNewData();
            {
                std::lock_guard guard{m_updatedDataMutex};
                m_updatedData = std::move(data);
            }
            PostThreadMessage(m_mainThreadId, WM_MY_UPDATE_DATA, 0, 0); // <- look ma, no pointer
        }
    }
    
    void Foo::onMyUpdateData() { // handles WM_MY_UPDATE_DATA
        std::lock_guard guard{m_updatedDataMutex};
        m_data = std::move(m_updatedData);
    }
    

    Einer der Vorteile dieser Technik ist dass man sicher sein kann, dass sich m_data nicht während der Ausführung eines anderen Message Handlers ändern kann. Und das auch ohne dass man die Mutex die ganze Zeit über gelockt halten müsste. D.h. automatisch auch dass man die Mutex bei Zugriff auf m_data nicht locken muss. Das kann einem das Leben schon einfacher machen.



  • @It0101 sagte in Datenaustausch zwischen thread?:

    @Quiche-Lorraine sagte in Datenaustausch zwischen thread?:

    Raymond Chen

    1. Muss man den kennen? 😃

    Muss nicht. Ergibt sich aber irgendwann von selbst wenn man genug Win32 Zeugs macht.



  • @hustbaer sagte in Datenaustausch zwischen thread?:

    Egal. Shared memory Multithreading hat auch so seine Probleme. Ich bleibe dabei: es kommt drauf an was besser ist, und es gibt Fälle wo Kommunkation mittels Window-Messages das Mittel der Wahl ist. Probleme mit nicht freigegebenen "Kommunikationspuffern" kann man auch vermeiden indem man nur eine "es gibt was zum Updaten" Message schickt, und die neuen Daten in eine Membervariable steckt. Zugriff synchronisiert über eine Mutex. Ala

    das is gut, so werde ich es auch umsetzen;)

    @hustbaer sagte in Datenaustausch zwischen thread?:

    Stimmt. Und da sollte man nicht anfangen das zu ignorieren, weil man sonst echte Leaks nicht mehr findet.

    ja genau deswegen bin ich da pingelig gewesen;)



  • Jetzt habe ich noch ein "leak" :

    Detected memory leaks!
    Dumping objects ->
    {16203} normal block at 0x02CF82A8, 0 bytes long.
     Data: <> hû=
    Object dump complete.
    

    0 bytes groß!? kann mir jemand sagen wie ich das intepretieen soll?:)



  • Naja man kann auch malloc(0) sagen. Ist voll OK. Gibt eine Adresse zurück die man dann wieder mit free freigeben darf -- aber sonst halt nix. Gibt ein paar Situationen wo man sich durch die Regel ein paar "if"s spart.

    ps: Der Returnwert von malloc(0) darf NULL sein, selbst wenn noch genügend Speicher vorhanden wäre. Dadurch wird das Feature etwas weniger nützlich. Eine Implementierung darf malloc(0) aber auch so implementieren dass eine gültige Adresse zurückgegeben wird, die man bloss nicht dereferenzieren darf, weil sie ja auf einen "0 Byte Block" zeigt.



  • @hustbaer sagte in Datenaustausch zwischen thread?:

    Naja man kann auch malloc(0) sagen. Ist voll OK. Gibt eine Adresse zurück die man dann wieder mit free freigeben darf -- aber sonst halt nix. Gibt ein paar Situationen wo man sich durch die Regel ein paar "if"s spart.
    ps: Der Returnwert von malloc(0) darf NULL sein, selbst wenn noch genügend Speicher vorhanden wäre. Dadurch wird das Feature etwas weniger nützlich. Eine Implementierung darf malloc(0) aber auch so implementieren dass eine gültige Adresse zurückgegeben wird, die man bloss nicht dereferenzieren darf, weil sie ja auf einen "0 Byte Block" zeigt.

    ich habe tatsächlich an eine Stelle eine "new char[0]" gemacht... 🙂 jetzt is das leak weg;) Ok Dachte wirklich. dass bei einem 0 byte großem buffer ein nullptr zurück kommt, aber wäre dann inkonsequent im verhalten:)



  • Bei new T[0] ist es glaub ich sogar garantiert dass nicht nullptr zurückkommt.


Anmelden zum Antworten