Thread-safety

Hi,

I'm not very used to thread-safety and synchronization and stuff like that but I have this piece of code that I want to be thread-safe and I'm out of idea.
The problem is the cbt_proc variable that CBTProc needs to unhook the procedure.
I can't pass data to CBTProc so I really need that variable. But if two threads call a message box at the same time something can go wrong and not work as intented. Basically, this little class is just used to make MessageBox centered in the owner window.
What are my options to achieve what I'm expecting.


MsgBox.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class WndMessageBox
{
private:
	HWND owner_;
	LPCWSTR text_;
	LPCWSTR caption_;
	UINT type_;
	
	static HHOOK cbt_proc;
	
	static LRESULT CALLBACK CBTProc(INT code, WPARAM wparam, LPARAM lparam);
public:
	
	WndMessageBox(HWND owner, LPCWSTR text, LPCWSTR caption, UINT type);
	
	INT show();
};



MsgBox.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

HHOOK WndMessageBox::cbt_proc;

WndMessageBox::WndMessageBox(HWND owner, LPCWSTR text, LPCWSTR caption, UINT type) :
	owner_{ owner },
	text_{ text },
	caption_{ caption },
	type_{ type }
{
}

INT WndMessageBox::show()
{
	if (owner_ != nullptr)
	{
		cbt_proc = ::SetWindowsHookExW(WH_CBT, CBTProc, nullptr, ::GetCurrentThreadId());
	}
	return ::MessageBoxW(owner_, text_, caption_, type_);
}

LRESULT CALLBACK WndMessageBox::CBTProc(INT code, WPARAM wparam, LPARAM lparam)
{
	if (code == HCBT_ACTIVATE)
	{
		WndCenter(HWND(wparam), ::GetParent(HWND(wparam)));
		::UnhookWindowsHookEx(cbt_proc);
	}
	return ::CallNextHookEx(nullptr, code, wparam, lparam);
}

It seems that my options are mutex or critical section. I think critical sections are best for what I'm doing but I would like to know if it's ok to enter a critical section in one method and leave it in another. See the code below...


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static CriticalSection wnd_msgbox_cs;

//
HHOOK WndMessageBox::cbt_proc;

//
INT WndMessageBox::show()
{
    if (owner_ != nullptr)
    {
        cbt_proc = SetWindowsHookExW(WH_CBT, CBTProc, nullptr, GetCurrentThreadId());
        if (cbt_proc != nullptr)
        {
            wnd_msgbox_cs.lock();
        }
    }
    return MessageBoxW(owner_, text_, caption_, type_);
}

//
LRESULT CALLBACK WndMessageBox::CBTProc(INT code, WPARAM wparam, LPARAM lparam)
{
    if (code == HCBT_ACTIVATE)
    {
        WndCenter(HWND(wparam), GetParent(HWND(wparam)));
        UnhookWindowsHookEx(cbt_proc);
        wnd_msgbox_cs.unlock();
    }
    return CallNextHookEx(nullptr, code, wparam, lparam);
}

I'm pretty sure that critical sections and mutexes are exactly the same, but std mutexes works on more platforms. I highly recommend std::mutex because it's more readable, and a wider audience will understand.

Also I can't see enough code, or understand what api you are using to know what are the shared data and whats not, what I would do is lock the critical section/mutex for all the functions like in the mutex example, and see if you get any sigfaults.

The way how I multithread is by whenever something new happens (like if an entity is created, an entity does something or a windows has popped up I guess) I would put it into a queue that holds functions, from <functional>, and I would have 2 worker threads in a thread pool do the jobs.

I would recommend reading a book called "C++ Concurrency in Action" on chapter 3 it talks about all the ways on how to let multiple threads share data without having 2 modifying the data at the same time, almost all the examples use mutexes, but there are many ways to use them. It might tell you what you are looking for, but it also tells you everything you should know about multithreading.*cough*http://gen.lib.rus.ec/*cough*
Topic archived. No new replies allowed.