Threads + read/write



  • Hi : >
    Wie der Titel schon sagt, habe ich Threads und möchte eine read/write-Klasse dafür schreiben... Nur scheint sie so, wie ich sie habe nicht nur hässlich (ineffektiv) sondern au noch fehlerhaft zu sein -.-
    Kann mir evtl jmd nen Tut oder so empfehlen? Wichtig wäre nur, dass das nicht nur ein Tut aka:
    CreateMutex (....);
    WaitFor....
    ReleaseMutex (...);
    ist, sondern auch wirklich beschrieben wird, wie man die Lese-Zugriffe mit den Schreibenden am besten verknüpft...
    Danke schon mal...



  • Also das hab ich bisher:

    class threads
    	{
    		private:
    			const HANDLE notwrite, notread, notrcount;
    			signed __int32 rcount;
    		protected:
    			threads (const bool isfree) :	notwrite (CreateEvent (NULL, false, isfree, NULL)),
    											notread (CreateEvent (NULL, false, true, NULL)),
    											notrcount (CreateEvent (NULL, false, true, NULL)),
    											rcount (0)
    				{};
    			void destruct (const bool havetolock)
    				{
    					if (havetolock)		write_lock ();
    					CloseHandle (notwrite);
    					CloseHandle (notread);
    					CloseHandle (notrcount);
    				};
    		public:
    			void read_lock (void)
    				{
    					WaitForSingleObject (notwrite, INFINITE);
    					WaitForSingleObject (notread, 0);
    					WaitForSingleObject (notrcount, INFINITE);
    					SetEvent (notwrite);
    					++rcount;
    					SetEvent (notrcount);
    				};
    			void read_unlock (void)
    				{
    					WaitForSingleObject (notrcount, INFINITE);
    					if (rcount > 1)
    						{
    							--rcount;
    						}
    						else
    							{
    								rcount = 0;
    								SetEvent (notread);
    							}
    					SetEvent (notrcount);
    				};
    			void write_lock (void)
    				{
    					WaitForSingleObject (notwrite, INFINITE);
    					WaitForSingleObject (notread, INFINITE);
    				};
    			void write_unlock (void)
    				{
    					SetEvent (notwrite);
    					SetEvent (notread);
    				};
    	};
    

    Würd mich sehr über Verbesserungsvorschläge freuen... Aber sie sollten Thread-Übergreifend sein:

    read_lock ();
    _beginthreadex (NULL, 0, &command, this, 0, NULL); //und da kommt dann erst das read_unlock ()
    

    Danke schon mal - auch, wenn es viel zu lesen ist und wahrscheinlich fürchterlich umständlich / schlecht ist 😞



  • schau dir das mal an: http://www.relisoft.com/win32/active.html

    das von kansnt ableiten



  • Danke...

    aber:

    1. 'for the duration of its lifetime your object is protected from any other threads' Ist es unsauber, die Daten in einem Thread zu locken und dann in nem anderen zu nutzen und zu unlocken? Oo (das disqualifiziert Mutex bzw Critical-Sections leider)

    2. sieht meine Event-Klasse denn so scheiße aus, dass du mir eine 10-Zeilen lange schickst, die viiiiiiieeeeel weniger kann, als ich bis her habe?



  • Würd mich sehr über Verbesserungsvorschläge freuen... Aber sie sollten Thread-Übergreifend sein:

    Irgendwie kommt mir der Code SEHR bekannt vor. Und er ist immernoch gleich furchtbar.

    Thread-Übergreifend wären Semaphoren, damit kann man auch einen Reader-Writer-Lock machen. Ich würde aber nie so synchronisieren, weil es fehleranfällig ist, und mir auch einfach kein Beispiel einfällt wo es Sinn machen würde.

    Reader-Writer-Locks sind generell oft ein Fehler (weil komplizierter und langsamer als "normale" Mutexen).



  • Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum Rund um die Programmierung verschoben.

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

    Dieses Posting wurde automatisch erzeugt.



  • Hmmm... So ist es aber auch nicht besser, oder? (Doppelpunkt ^^)

    extern signed __int16 MaxReading;
    
    class threads
    	{
    		private:
    			const HANDLE notread;
    			CRITICAL_SECTION notwrite;
    			inline void _read_lock (void)
    				{
    					WaitForSingleObject (notread, INFINITE);
    				};
    		protected:
    			threads (const bool isfree) : notread (CreateSemaphore (NULL, MaxReading, MaxReading, NULL))
    				{
    					InitializeCriticalSection (&notwrite);
    					if (!isfree)
    						EnterCriticalSection (&notwrite);
    				};
    
    			void destruct (const bool havetolock)
    				{
    					if (havetolock)
    						write_lock ();
    					CloseHandle (notread);
    					DeleteCriticalSection (&notwrite);
    				};
    		public:
    			void read_lock (void)
    				{
    					_read_lock ();
    					EnterCriticalSection (&notwrite);
    					LeaveCriticalSection (&notwrite);
    				};
    
    			void read_unlock (void)
    				{
    					ReleaseSemaphore (notread, 1, NULL);
    				};
    
    			void write_lock (void)
    				{
    					EnterCriticalSection (&notwrite);
    					for (signed __int16 i (0); i < MaxReading; ++i)
    						{
    							_read_lock ();
    						}
    					ReleaseSemaphore (notread, MaxReading, NULL);
    				};
    
    			void write_unlock (void)
    				{
    					LeaveCriticalSection (&notwrite);
    				};
    	};
    


  • Dieser Thread wurde von Moderator/in rüdiger aus dem Forum Rund um die Programmierung 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.



  • Nein, ist nicht besser.
    Wenn du seit damals als du das erst mal einen Thread zu dem Thema erstellt hast nicht gelernt hast wie man das macht dann lass es.



  • Wie soll man es denn unbedingt machen?
    So bald das lesen (unendlich oft zur gleichen Zeit) und schreiben da reinkommt, geht es ne mehr einfach nur mit Mutex bzw Events - und nur Semaphores würde zwar von der Logik her gehen aber wenn dann 2 Threads zur gleichen Zeit anfangen, die Semaphores zu unsetten, hat man nen Deadlock...
    Aber wenn du so gut bescheid weist, wie du tust, kannst du mir ja vll auch mal nen Tip geben...
    Danke...
    Hab es jetzt so und so geht es zumindest (und so unsauber/... find ich es auch nicht):

    class threads
    	{
    		private:
    			const HANDLE notread;
    			CRITICAL_SECTION notwrite;
    			const HANDLE writelocking;
    		protected:
    			threads (const bool isfree) : notread (CreateSemaphore (NULL, MaxReading, MaxReading, NULL)), writelocking (CreateEvent (NULL, false, true, NULL))
    				{
    					InitializeCriticalSection (&notwrite);
    					if (!isfree)
    						EnterCriticalSection (&notwrite);
    				};
    
    			void destruct (const bool havetolock)
    				{
    					if (havetolock)
    						write_lock ();
    					CloseHandle (notread);
    					DeleteCriticalSection (&notwrite);
    				};
    		public:
    			inline void read_lock (void)
    				{
    					WaitForSingleObject (notread, INFINITE);
    					EnterCriticalSection (&notwrite);
    					LeaveCriticalSection (&notwrite);
    				};
    
    			inline void read_unlock (void)
    				{
    					ReleaseSemaphore (notread, 1, NULL);
    				};
    
    			inline void write_lock (void)
    				{
    					WaitForSingleObject (writelocking, INFINITE);
    					for (signed __int16 i (0); i < MaxReading; ++i)
    						{
    							WaitForSingleObject (notread, INFINITE);
    						}
    					EnterCriticalSection (&notwrite);
    					SetEvent (writelocking);
    					ReleaseSemaphore (notread, MaxReading, NULL);
    				};
    
    			inline void write_unlock (void)
    				{
    					LeaveCriticalSection (&notwrite);
    				};
    	};
    

    PS:
    da ich jz eh noch nen einzelnes Event für write_lock brauch könnte man die criticalsection auch gleich weglassen und alles mit semaphores machen - kein Plan, ob sich das was nimmt - wahrscheinlich aber schon ^^



  • Du brauchst *nur* eine Semaphore, sonst garnix.
    Der Event und die CRITICAL_SECTION sind komplett überflüssig.

    class reader_writer_lock
        {
                reader_writer_lock() : m_semaphore(::CreateSemaphore(0, MaxReading, MaxReading, 0))
                    {
                        if (!m_semaphore)
                            throw std::runtime_error("CreateSemaphore failed.");
                    }
    
                ~reader_writer_lock
                    {
                        ::CloseHandle(m_semaphore);
                    }
    
                void read_lock()
                    {
                        ::WaitForSingleObject (m_semaphore, INFINITE);
                    }
    
                void read_unlock ()
                    {
                        ::ReleaseSemaphore(m_semaphore, 1, 0);
                    }
    
                void write_lock()
                    {
                        for (size_t i = 0; i < MaxReading; i++)
                            ::WaitForSingleObject (m_semaphore, INFINITE);
                    }
    
                void write_unlock ()
                    {
                        ::ReleaseSemaphore(m_semaphore, MaxReading, 0);
                    }
    
            private:
                const HANDLE m_semaphore;
        };
    

    BTW: du hast einen Haufen überflüssiger Semikolons, und schreckliche Namen ("notwrite").



  • Was passiert jz bei dir:
    Thread1:
    write_lock ();
    zur gleichen Zeit im Thread2:
    write_lock ();

    Weist du genau so gut, wie ich, was passiert? ^^

    Deshalb brauch ich ein Semaphore UND ein Event...

    die namen find ich nicht schlimm - komm gut damit zu recht 😛
    die semikoli sind gewohnheit - stören nicht und wenn ich ne Klammer vergess kommen keine Millionen Fehler sondern nur nen paar... (dafür hast du nen paar :: zu viel ^^ sind genau so unnötig, oder hab ich da was verpasst? Oo)

    Bye 😛


Anmelden zum Antworten