Locked im gleichen Thread.



  • Das Beispiel sagt alles:

    void bla()
    {
        std::unique_lock <std::mutex> lock{mut, std::try_to_lock};
        
        // kann ich hier prüfen ob schonmal in dem selben Thread gelockt wurde und ich deshalb,
        // den lock nicht kriege? 
        if (lock.owns_lock()) { /* ... */}
    }
    

    Mir wär es wichtig zu differenzieren. Ich will nicht einfach ein recursive mutex verwenden sondern wissen ob ich gerade aus dem selben thread komme oder nicht.



  • Soweit ich weiss geht das mit std::mutex so direkt nicht. Du kannst dir aber auf Basis von std::mutex eine eigene Mutex bauen mit der das geht.

    Grob skizziert:

    #include <mutex>
    #include <thread>
    #include <atomic>
    
    class smart_mutex {
    public:
        bool try_lock() {
            if (!m_mutex.try_lock())
                return false;
    
            post_lock();
            return true;
        }
    
        void lock() {
            m_mutex.lock();
            post_lock();
        }
    
        void unlock() {
            pre_unlock();
            m_mutex.unlock();
        }
    
        std::thread::id owner() const {
            return m_owner.load(std::memory_order_acquire);
        }
    
        bool is_owned_by_this_thread() const {
            return owner() == std::this_thread::get_id();
        }
    
    private:
        void post_lock() {
            set_owner(std::this_thread::get_id());
        }
    
        void pre_unlock() {
            set_owner(std::thread::id{});
        }
    
        void set_owner(std::thread::id o) {
            m_owner.store(o, std::memory_order_release);
        }
    
        std::mutex m_mutex;
        std::atomic<std::thread::id> volatile m_owner;
    };
    


  • Das selbe nur mit ner rekursiven Mutex hab ich in einem Projekt verwendet um sicherzustellen dass an Stellen wo "temporär entsperrt" werden muss (wegen Condition Variable) nicht rekursiv gelockt war. Dazu hab ich ähnlich wie im Beispiel oben eine size_t locked_by_this_thread() const Funktion gemacht die 0, 1 oder > 1 zurückgegeben hat, wobei > 1 eben hiess: ja, dieser Thread ist der Owner, aber mehr als 1x.

    Die nötige Assertion ist dann trivial:

    void foo::fun() {
        std::unique_lock<std::mutex> lock{ m_mutex };
        assert(m_mutex.locked_by_this_thread() == 1);
        // Do condition-variable stuff
    }
    

    Wenn man es öfter braucht könnte man sich auch eine non_recursive_unique_lock Klasse basteln die das entsprechende Assert enthält bzw. was man sonst als Reaktion haben möchte.



  • @5cript
    Ohne die genauen Hintergründe zu kennen, ist es schwierig eine Empfehlung auszusprechen. Aber prinzipiell halte ich recursive mutex Modelle doch für sehr fragwürdig. Wäre dein Problem nicht mit der Unterteilung in 2 Funktionen gelöst? Ebene eine interne (ohne lock) und eine externe (die, die den lock eben anzieht) Funktion.

    void bla()
    {
        std::unique_lock <std::mutex> lock{mut, std::try_to_lock};
    
        bla_internal();
    }
    
    void bla_internal()
    {
        bla_internal();
    }
    


  • @hustbaer Danke, genau so brauch ich das!

    @DNKpp Das ist leider alles nicht so einfach. Ich habe auf einem Embedded System events die aus verschiedenen Threads feuern und die werden alle an einem Punkt synchronisiert.
    Ich darf nur mit einem Thread auf dem Display schreiben, sonst gibts Pixelbrei.
    Aber wenn ich aus dem selben Thread komme brauch/darf ich nicht locken. Ob ich das tu war festzustellen.

    Warum ein recursive mutex dafür nicht funktioniert habe ich vergessen. Weil klingt total nach dem Anwendungsfall danach. Hatte das getauscht und plötzlich ging gar nichts mehr XD.
    Hab das auch grad nicht vor Augen/Zugang zum Code.


Log in to reply