CreateMutex ..WaitForSingleObject Locked nicht



  • Hallo Leute ,

    ich habe eine Mutex Klasse geschrieben.

    Allerding block Lock nicht!? Wenn ich Lock zweimal hintereinander aufrufe, sollte er doch eigentlich blocken bis ich Unlock aufrufe? Mache ich was falsch? Denkfehler?

    #pragma once
    
    class Mutex
    {
    	HANDLE _handle;
    
    public:
    	Mutex();
    	virtual ~Mutex();
    	int Lock();
    	bool Unlock();
    };
    
    #include <exception>
    #include "Mutex.h"
    
    Mutex::Mutex()
    {
    	_handle = CreateMutex(NULL,FALSE,NULL);
    	if(NULL == _handle)
    		throw std::exception("Mutex");
    }
    
    int Mutex::Lock()
    {
    	return WaitForSingleObject(_handle,INFINITE);// != WAIT_OBJECT_0; //todo: Abondend
    }
    
    bool Mutex::Unlock()
    {
    	return ReleaseMutex(_handle) == 0;
    }
    
    Mutex::~Mutex()
    {
    	CloseHandle(_handle);
    }
    


  • Der Code sieht auf den 1. Blick mal so aus als ob er funktionieren sollte.
    Ein paar Dinge würde ich ändern, aber wenn du die Klasse nicht komisch verwendest sollten diese Dinge keine Fehler verursachen:

    1. Eine Mutex Klasse sollte nicht kopierbar sein. Deine implementiert auch die Kopier-Semantik nicht korrekt -> am besten non-copyable machen. Einfachster Weg das zu erreichen: Move-Konstruktor als deleted markieren:
    class Mutex
    {
    	HANDLE _handle;
    
    public:
    	Mutex(Mutex&&) = delete;
    	Mutex();
    ...
    
    1. Ich würde die Klasse final machen und dann natürlich auch den dtor non-virtual - von einer Mutex ableiten finde ich komisch.
    2. Ich würde von den Lock und Unlock Funktionen nichts zurückgeben. Wenn du es als Teil des Contracts von Mutex siehst dass sie eine Win32 Mutex kapselt, dann ist es OK so wie du es machst. Wenn der Contract aber nur sein soll dass die Klasse das Konzept "mutex" implementiert, dann würde ich die Funktionen auf void umstellen. Das ermöglicht dir dann jederzeit etwas anderes zu verwenden wie z.B. einen CRITICAL_SECTION oder nen SRW lock. (Was vermutlich besser wäre, weil die beide deutlich schneller sind als Win32 Mutexen.)

    Zeig mal den Code her von dem du erwartest dass er blocken sollte, der aber nicht blockt.

    Bzw. falls es daran liegt: Wenn du erwartest dass hier

    Mutex m;
    m.Lock();
    m.Lock();
    

    das 2. Lock blocken sollte - das ist nicht so. Eine Win32 Mutex ist "reentrant", d.h. die kannst du im selben Thread mehrfach locken. Pro erfolgreichem Lock (WaitForSingleObject) ist dann auch ein ReleaseMutex nötig. Damit was blockt müsstest du die Mutex in einem Thread locken und dann in einem anderen Thread nochmal Lock aufrufen. Der 2. Thread muss dann warten bis der 1. Thread Unlock aufruft.



  • Guten Morgen hustbear,

    vielen Dank. Ja ich habe auch Lock und Unlock ursprünglich als void deklariert , um herauszufinden warum es aber nich funktioniert habe ich das zurück gegeben. Später wollte ich noch TryLock machen.. welcher mit dann ein false zurück geben kann fall schon gelockt wurde ,

    Genau das "reentrant" Thema is mir dann eingefallen, und ich dachte "AHAAA".. Aber dem war dann nicht so, ich hatte das erste Lock im UI Thread gemacht, und das zweite in einem neu erzeugten Thread. Und Lock blockierte trotzdem nicht:(

    Hier der Code Auschnitt, in dem ich das teste :
    (Meine Thread Tick munter weiter, obwohl das eigentlich nicht dürfte, da ich davor im UI Thread schon locke)

    UINT CDialogMfcAppDlg::MFCThreadProc(LPVOID lpParameter)
    {
    	while(WaitForSingleObject(_timerHandle,1000) == WAIT_TIMEOUT)
    	{
    		HWND dlg = GetSafeHwnd();
    		::PostMessage(dlg, WM_ON_ADD_ITEM, 0, 0);
    	}
    	return 0;
    }
    
    static UINT MFCThreadProc1(LPVOID lpParameter)
    {
    	CDialogMfcAppDlg* pt = (CDialogMfcAppDlg*)lpParameter;
    	return pt->MFCThreadProc(NULL);
    }
    
    LRESULT CDialogMfcAppDlg::OnThreadMessage(WPARAM wParam, LPARAM lParam)
    {
    	UNREFERENCED_PARAMETER(lParam);
    	UNREFERENCED_PARAMETER(wParam);
    	_mutex.Lock(); /* Lcok new Thread */
    	_outputList->AddString(_T("Tick"));
    	_mutex.Unlock();
    	return 0;
    }
    
    BOOL CDialogMfcAppDlg::OnInitDialog()
    {
    	CDialog::OnInitDialog();
    
    	_outputList = static_cast<CListBox*>(this->GetDlgItem(IDC_LIST1));
    	_outputList->AddString(_T("First Lock"));
    
    	_mutex.Lock(); /* lock UI THREAD */
    	AfxBeginThread(MFCThreadProc1,this);
    }
    

    EDIT: @hustbaer , ich ziehe wieder mal den HUT vor dir;) MIST .. ich locke ja wieder im UI Thread, nicht im zweiten Thread.. wenn ich Lock in "MFCThreadProc" dann tut er das was ich will;) Danke für den Denkanstoß frohe Ostern;)


Log in to reply