try_lock und weitergeben



  • @Tim06TR
    Beschreib mal bitte etwas genauer was du machen möchtest. Ist mir nämlich nicht so ganz klar.
    Und schreib auch dazu ob dein Compiler C++11 kann.

    Ansonsten... falls das relevant sein sollte: ne Mutex darfst du nur aus dem Thread wieder freigeben der sie auch gelockt hat. Wenn du in einem Thread locken willst, dann an einen anderen übergeben und dort dann später unlocken, dann musst du nen binären Semaphor statt ner Mutex nehmen. Bei nem Semaphor ist das nämlich erlaubt.



  • ja C++11 ist alles super, bis auf threads (mingw - gcc 4.8.1)

    ---------------------------------------------------------------------------------------
    Zunächst: Ich habe meine Frage falsch und schlecht gestellt.
    ---------------------------------------------------------------------------------------

    Ich habe mir einen Puffer erdacht, in den ich gleichzeitig lesen und schreiben kann mit mindestens einem Lesethread und mindestens einem Schreibthread.
    Der Puffer besteht aus einer Queue mit shared_array Instanzen (="chunk").
    Durch "grab_w" wird ein Chunk erstellt (bis zu einem maximum) und gibt ihn zurück, damit er mit Daten gefüllt werden kann.
    Die Funktion "grab_r" gibt ein Chunk zurück, der nicht mehr außerhalb verwendet wird (von einem grab_w aufruf) (in richtiger Reihenfolge, daher queue).
    Außerdem wird er aus der queue entfernt.

    Ich scheitere gerade an dem wrapper, der ein chunk enthält und automatisch die Klass "DataFeed" mitteilt, dass er nicht mehr verwendet / noch verwendet wird.

    Schematische Benutzung von "DataFeed":

    Hier mal schnell im Forum geschrieben:

    // Beispielhaftes Interface für die Klasse darunter:
    class DataFeed {
    public:
        class DataChunk {
            // ???
        };
    private:
        uint32_t max_queue_size_;
        uint32_t chunk_size_;
        std::queue </* ??? */> queue_;
    
        void wait_r_avail() const; // verwendet vielleicht std::conditional_variable
        void wait_w_avail() const; // blockiert solange queue_.size() == max_queue_size_
    
        DataChunk grab_w(); // impl ?
        DataChunk grab_r(); // impl ?
    };
    
    // ok der Klassenname ist jetzt doof, aber ich editiere ihn nicht, falls schon jemand angefangen hat den zu zitieren.
    class asnyc_rw {
    private:
        thread reader_;
        thread writer_;
        DataFeed buffer_;
        std::atomic_long_long remaining_; // remaining data
        uint32_t chunk_size_; // im ctor erhalten und an DataFeed weitergereicht
    
    private:
        void read();
        void write();
    
    public:
        void transfer();
    
        // mehr (ctor, dtor, ...)
    };
    //-------------------------------------------------------------------------------------------------------------------
    void async_rw::transfer() {
        reader_ = thread(std::bind(&async_rw::read, this));
    
        write(); // evtl später in thread "writer_"
    }
    //-------------------------------------------------------------------------------------------------------------------
    void async_rw::read() {
        std::ifstream file ("somewhere", std::ios_base::binary);
        do {    
            buffer_.wait_w_avail(); // blockiert solange die queue ihre maximale Größe hat. Sollte zu Beginn niemals blockieren
            auto chunk = buffer_.grab_w(); // hat chunk_size_ größe
            file.read(chunk.get(), chunk_size_); // oder ähnlich
        } while (file.gcount());
    
        // lese daten von festplatte oder sonstwo her und speicher sie in chunk
    
        // chunk läuft out of scope und wird damit verfügbar durch die Funktion "buffer_.grab_r"
        // Die blockierende Funktion "buffer_.wait_r_avail()" lässt nun ein Mal durch (zB. std::conditional_variable::notify_one()) und ist danach wieder blockierend
    }
    //-------------------------------------------------------------------------------------------------------------------
    void async_rw::write() {
        while (remaining_.load()) {
            buffer_.wail_r_avail();        // verwendet vielleicht std::conditional_variable
            auto chunk = buffer_.grab_r(); // soll wenn obige Funktion fälschlicherweise nicht verwendet wird geworfen
    
            // verschicke "chunk" mit socket
        }
    }
    //-------------------------------------------------------------------------------------------------------------------
    


  • Mir scheint, Du brauchst nur eine Semaphore zu benutzen.



  • Mal am Rande: Bei einem Test:

    std::atomic_bool b;
    b.store(true);
    
    std::shared_ptr <std::atomic_bool> spb;
    spb->store(true); // BOOOOOMMMM (SIGSEV in "void store(/* ... */) noexcept"
    

    wie gesagt GCC 4.8.1 (mingw)

    Was habe ich hier verletzt?

    EDIT: haha shred_ptr :D... hammer Tippfehler



  • Tim06TR schrieb:

    Was habe ich hier verletzt?

    Dein Pointer zeigt auf kein Objekt.



  • volkard schrieb:

    Tim06TR schrieb:

    Was habe ich hier verletzt?

    Dein Pointer zeigt auf kein Objekt.

    uuuoooopppsss

    ok ich geh schlafen 😃 *derp*



  • Ok, habe das ganze nun hinbekommen, genauso wie ich es wollte. Ich bin mir aber sicher, dass man es noch sauberer hätte machen können.
    Ich verwende 2 shared_ptr mit atomics, 1 conditional_variable (n), einen shared_ptr mit einem mutex, sowie einen Instanzenzähler. Alles pro Chunk.

    EDIT: Ich habe nicht die Zeit von vorhin bis jetzt gebraucht, ich habe noch eine andere Codestelle umgebaut.



  • Lies http://de.wikipedia.org/wiki/Erzeuger-Verbraucher-Problem und schau, ob es besser passen würde.



  • Sone schrieb:

    Zugriff auf den mutex von 2 verschiedenen Orten.

    Was soll daran ein Problem sein? Mutexe selbst sind ein atomic_bool mit drumherum. Die sind völlig Threadsafe, sonst würde ja rein gar nichts funktionieren.

    Das klingt fast wie:

    Ein Betriebssystem ist ein

    void main() { }
    

    mit drumherum. 😃



  • Natürlich implementiert ein Mutex sehr viel nützliches Verhalten. Der Kernpunkt ist aber, dass die einzigen Member von mutex atomar sind.


Anmelden zum Antworten