mutex schreiben



  • hä?



  • dot schrieb:

    hä?

    ich meinte, vielleicht gibts ja eine bessere lösung als die triviale aus deinem vorschlag.

    dein ansatz hat zudem das problem, dass lesezugriff von mehreren threads gleichzeitig nicht funktioniert, weil read() dann blockiert.



  • 🤡 stimmt



  • locker schrieb:

    hintergrund ist: ich hätte gern ein mutex dass für schreib- und lesezugriffe getrennt gelockt werden kann (schreibzugriff soll blockieren bis nicht mehr gelesen und geschrieben wird, lesezugriff nur bis nicht mehr geschrieben wird). criticalsections scheinen das nicht leisten zu können.

    Schonmal über Semaphore nachgedacht?



  • CStoll schrieb:

    Schonmal über Semaphore nachgedacht?

    noch nicht wirklich - sah auf den ersten blick in windows recht aufwendig und potenziell langsam aus. ich schaus mir mal genauer an.



  • locker schrieb:

    sah auf den ersten blick in windows recht aufwendig und potenziell langsam aus

    das sind mutexe auch :p



  • ist mein code nich rein C++?



  • Nein, der nutzt die WinAPI. Reines C++ kennt keine Multithreading-Ansätze und keine Synchronisation.



  • Read-Write-Mutexen sind IMO grundsätzlich problematisch.

    Spätestens dann wenn man die Möglichkeit will einen Read-Lock auf einen Write-Lock "upzugraden". Dann muss nämlich (in manchen Fällen) der Read-Lock temporär hergegeben werden, bis ein Write-Lock geholt werden kann. Und das ist etwas was Programmierer die mit der fertigen Klasse arbeiten gerne übersehen werden - d.h. die werden davon ausgehen dass das was sie vor dem "upgrade" gelesen haben auch nach dem "upgrade" noch so ist -- was aber eben nicht so sein muss.



  • ich habe jetzt mal http://doc.trolltech.com/qq/qq11-mutex.html mit windows-mitteln umgesetzt. gibts daran irgendwas auszusetzen? vielleicht irgendwelche nicht offensichtlichen fallen?

    der thread ist hier mittlerweile offtopic, kann gerne nach winapi verschoben werden.



  • BorisDieKlinge schrieb:

    ist mein code nich rein C++?

    Schlag doch einfach mal im C++-Standard oder www.cppreference.com folgende Ausdücke nach:

    BorisDieKlinge schrieb:

    ...
    CRITICAL_SECTION ...
    InitializeCriticalSection...
    DeleteCriticalSection...
    EnterCriticalSection...
    LeaveCriticalSection...
    TryEnterCriticalSection...
    

    😉

    Gruß,

    Simon2.



  • um mir mal schizomäßig selbst zu antworten:

    locker schrieb:

    vielleicht irgendwelche nicht offensichtlichen fallen?

    in criticalsections kann der selbe thread mehrfach eintreten ohne zu blockieren. bei semaphoren geht das nicht. 😞



  • Klar geht das bei semaphoren.



  • Tyrdal schrieb:

    Klar geht das bei semaphoren.

    nicht bei windows-semaphoren, dazu müsste ich wohl meine eigene schreiben.



  • locker schrieb:

    um mir mal schizomäßig selbst zu antworten:

    locker schrieb:

    vielleicht irgendwelche nicht offensichtlichen fallen?

    in criticalsections kann der selbe thread mehrfach eintreten ohne zu blockieren. bei semaphoren geht das nicht. 😞

    Und, wo ist das Problem?
    Statt der QMutex nimmst du ne Critical Section und statt der QSemaphore eben ne Windows Semaphore, das passt schon alles.

    Dann hast du einen schön langsamen Read-Write-Lock gebastelt 🙂



  • hustbaer schrieb:

    Statt der QMutex nimmst du ne Critical Section und statt der QSemaphore eben ne Windows Semaphore, das passt schon alles.

    tuts nicht. momentan habe ich keine unterscheidung zwischen lesen und schreiben drin. und es wird mit einer critical section synchronisiert, welche ja problemlos mehrfach im gleichen thread gelocked werden kann, davon geht der bestehende code auch aus. das funktioniert mit einer semaphore nicht, weil die sich einen dreck drum schert, welcher thread locked.



  • Ich dachte du willst dieses Qt Ding nachbasteln, und das geht mit CS + Semaphore, das meinte ich. Denn das Qt Ding ist anscheinend nicht darauf ausgelegt rekursiv gelockt werden zu können, kann also genau das nicht was du willst.

    Du könntest sowas in der Art machen (ich übernehme keine Garantie für irgendwas, hab das nur eben schnell zusammengehackt, und ohne condition variablen ist das echt doof zu programmieren):

    struct handle_guard
    {
    	explicit handle_guard(HANDLE h = 0)
    		:	m_h(h)
    	{
    	}
    
    	~handle_guard()
    	{
    		if (m_h != 0 && m_h != INVALID_HANDLE_VALUE)
    		{
    			bool rc = ::CloseHandle(m_h) != 0;
    			assert(rc);
    		}
    	}
    
    	HANDLE m_h;
    };
    
    struct critical_section
    {
    	critical_section()
    	{
    		::InitializeCriticalSection(&m_cs);
    	}
    
    	~critical_section()
    	{
    		::DeleteCriticalSection(&m_cs);
    	}
    
    	CRITICAL_SECTION m_cs;
    
    	struct scoped_lock
    	{
    		scoped_lock(critical_section& cs, bool lock_now = true) :
    			m_cs(cs.m_cs),
    			m_is_locked(false)
    		{
    			if (lock_now)
    				lock();
    		}
    
    		~scoped_lock()
    		{
    			if (is_locked())
    				unlock();
    		}
    
    		bool is_locked() const
    		{
    			return m_is_locked;
    		}
    
    		void lock()
    		{
    			assert(!is_locked());
    			::EnterCriticalSection(&m_cs);
    			m_is_locked = true;
    		}
    
    		void unlock()
    		{
    			assert(is_locked());
    			::LeaveCriticalSection(&m_cs);
    			m_is_locked = false;
    		}
    
    		bool m_is_locked;
    		CRITICAL_SECTION& m_cs;
    	};
    };
    
    class read_write_mutex
    {
    public:
    	read_write_mutex() :
    		m_can_write_lock(::CreateEventA(0, false, false, 0)),
    		m_can_read_lock(::CreateEventA(0, false, false, 0)),
    		m_writer_thread_id(0),
    		m_write_lock_count(0),
    		m_read_lock_count(0),
    		m_waiting_readers_count(0),
    		m_waiting_writers_count(0)
    	{
    		if (m_can_write_lock.m_h == 0 || m_can_write_lock.m_h == INVALID_HANDLE_VALUE)
    			throw std::runtime_error("CreateEvent");
    		if (m_can_read_lock.m_h == 0 || m_can_read_lock.m_h == INVALID_HANDLE_VALUE)
    			throw std::runtime_error("CreateEvent");
    	}
    
    	void read_lock()
    	{
    		critical_section::scoped_lock l(m_cs);
    		m_waiting_readers_count++;
    		while (m_write_lock_count)
    		{
    			l.unlock();
    			DWORD rc = ::WaitForSingleObject(m_can_read_lock.m_h, INFINITE);
    			assert(rc == WAIT_OBJECT_0);
    			l.lock();
    		}
    		m_read_lock_count++;
    		m_waiting_readers_count--;
    		if (m_waiting_readers_count > 0)
    		{	// wake other readers
    			bool rc = ::SetEvent(m_can_read_lock.m_h) != 0;
    			assert(rc);
    		}
    	}
    
    	void read_unlock()
    	{
    		critical_section::scoped_lock l(m_cs);
    		assert(m_read_lock_count > 0);
    		assert(m_write_lock_count == 0);
    		m_read_lock_count--;
    		if (m_read_lock_count == 0 && m_waiting_writers_count)
    		{	// wake a writer
    			bool rc = ::SetEvent(m_can_write_lock.m_h) != 0;
    			assert(rc);
    		}
    	}
    
    	void write_lock()
    	{
    		critical_section::scoped_lock l(m_cs);
    		if (m_writer_thread_id == ::GetCurrentThreadId())
    		{
    			m_write_lock_count++;
    			return;
    		}
    
    		m_waiting_writers_count++;
    		while (m_read_lock_count || m_write_lock_count)
    		{
    			l.unlock();
    			DWORD rc = ::WaitForSingleObject(m_can_write_lock.m_h, INFINITE);
    			assert(rc == WAIT_OBJECT_0);
    			l.lock();
    		}
    		m_waiting_writers_count--;
    
    		m_writer_thread_id = ::GetCurrentThreadId();
    		m_write_lock_count = 1;
    	}
    
    	void write_unlock()
    	{
    		critical_section::scoped_lock l(m_cs);
    		assert(m_read_lock_count == 0);
    		assert(m_write_lock_count > 0);
    		assert(m_writer_thread_id == ::GetCurrentThreadId());
    
    		m_write_lock_count--;
    
    		if (m_write_lock_count == 0)
    		{
    			m_writer_thread_id = 0;
    			if (m_waiting_writers_count)
    			{	// wake a writer
    				bool rc = ::SetEvent(m_can_write_lock.m_h) != 0;
    				assert(rc);
    			}
    			else if (m_waiting_readers_count)
    			{	// wake a reader (which will then wake the other readers)
    				bool rc = ::SetEvent(m_can_read_lock.m_h) != 0;
    				assert(rc);
    			}
    		}
    	}
    
    private:
    	critical_section m_cs;
    	handle_guard m_can_write_lock;
    	handle_guard m_can_read_lock;
    
    	DWORD m_writer_thread_id;
    	size_t m_write_lock_count;
    	size_t m_read_lock_count;
    
    	size_t m_waiting_readers_count;
    	size_t m_waiting_writers_count;
    };
    


  • Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.


Anmelden zum Antworten