boost and winthreads

Michael Ost most at museresearch.com
Fri Apr 28 12:30:38 CDT 2006


Does boost::threads + wine threads == happiness?

I would like to use boost threads in my winelib application, but they
need to coexist with threads created using the windows APIs by 3rd party
plugin DLLs. I built a test app that uses the two and they appear to
share both a CRITICAL_SECTION and a boost::mutex fine, so it looks like
I am in the clear. But I don't have alot of confidence in my
understanding of how Wine implements threads, so I thought it would be
wise to ask.

Attached is my test program. To build and run:

$ wineg++ -c boost-win.cpp
$ wineg++ -o boost-win.exe.so boost-win.o -lboost_threads
$ wine ./boost-win.exe.so 

Cheers... mo

PS: thanks to whoever is responsible for wineg++. What a timesaver!

boost-win.cpp:

#include "boost/thread.hpp"
#include <pthread.h>			// pthread_create
#include <sys/resource.h>		// PRIO_PROCESS
#include <stdio.h>				// printf
#include <windows.h>			// CreateThread

#define INDENT "                    "

DWORD WINAPI CSTestA(void* arg)
{
	CRITICAL_SECTION* cs = (CRITICAL_SECTION*) arg;
	puts("in, try CS");
	
	::EnterCriticalSection(cs);
	puts("CS locked");

	sleep(2);
	puts("wake up");

	::LeaveCriticalSection(cs);
	puts("unlock");

	sleep(1);
	puts("wake up, try CS");

	::EnterCriticalSection(cs);
	puts("CS locked");

	sleep(1);
	puts("wake up");

	::LeaveCriticalSection(cs);
	puts("unlock");

	puts("out");
}

struct CSTestB
{
	CSTestB(CRITICAL_SECTION* cs) :
		m_criticalSection(cs)
	{
	}
	void operator()()
	{
		puts(INDENT "in, try CS");

		::EnterCriticalSection(m_criticalSection);
		puts(INDENT "CS locked");

		boost::xtime t;
		boost::xtime_get(&t, boost::TIME_UTC);
		t.sec += 3;
		boost::thread::sleep(t);
		puts(INDENT"wake up");

		::LeaveCriticalSection(m_criticalSection);
		puts(INDENT "unlocked, out");

		boost::xtime_get(&t, boost::TIME_UTC);
		t.sec += 3;
		boost::thread::sleep(t);
		puts(INDENT "out");
	}
	
	CRITICAL_SECTION* m_criticalSection;
};

struct MutexTestA
{
	MutexTestA(boost::mutex* mutex) :
		m_mutex(mutex)
	{
	}
	void operator()()
	{
		puts("in - try mutex");
		boost::xtime t;

		{ // scope
			boost::mutex::scoped_lock lock(*m_mutex);
			puts("mutex locked");

			boost::xtime_get(&t, boost::TIME_UTC);
			t.sec += 2;
			boost::thread::sleep(t);
			
			puts("wake up");
		}
		puts("unlock");

		boost::xtime_get(&t, boost::TIME_UTC);
		t.sec += 1;
		boost::thread::sleep(t);
		puts("wake up, try mutex");

		{ // scope
			boost::mutex::scoped_lock lock(*m_mutex);
			puts("mutex locked");

			boost::xtime_get(&t, boost::TIME_UTC);
			t.sec += 1;
			boost::thread::sleep(t);
			
			puts("wake up");
		}
		puts("unlock");

		puts("out");
	}
	
	boost::mutex* m_mutex;
};

DWORD WINAPI MutexTestB(void* arg)
{
	boost::mutex* mutex = (boost::mutex*) arg;
	
	puts(INDENT "in - try mutex");

	{ // scope
		boost::mutex::scoped_lock lock(*mutex);
		puts(INDENT "mutex locked");

		boost::xtime t;
		boost::xtime_get(&t, boost::TIME_UTC);
		t.sec += 3;
		boost::thread::sleep(t);
		
		puts(INDENT "wake up");
	}
	puts(INDENT "unlock");

	puts(INDENT "out");
}

int main(int argc, char *argv[])
{
	// boost blocks on CS held by winthread
	if (argc > 1 && memcmp(argv[1], "cs", 2) == 0) {
		puts("Testing CRITICAL_SECTIONS...\n");
		puts("    winThread and boostThread share a CRITICAL_SECTION.
winThread grabs");
		puts("    it and sleeps, while boostThread waits for winThread to wake
up and");
		puts("    release. Then vice-versa.");
		puts("");
		puts("winThread           boostThread");
		puts("----------------------------------");
		CRITICAL_SECTION* criticalSection = new CRITICAL_SECTION();
		::InitializeCriticalSection(criticalSection);
	
		DWORD junk;
		HANDLE winThread = ::CreateThread(NULL, 0, CSTestA, criticalSection,
0, &junk);
	
		// delay 'cause boost starts faster
		sleep(1);
		CSTestB boostTest(criticalSection);
		boost::thread boostThread(boostTest);
		
		boostThread.join();
		// todo: howto wait for winThread?	
	
		::DeleteCriticalSection(criticalSection);
		delete(criticalSection);
	}
	else if (argc > 1 && memcmp(argv[1], "mu", 2) == 0) {
		puts("Testing boost::mutex...\n");
		puts("    winThread and boostThread share a boost::mutex. boostThread
grabs");
		puts("    it and sleeps, while winThread waits for boostThread to wake
up and");
		puts("    release. Then vice-versa.");
		puts("");
		puts("boostThread         winThread");
		puts("----------------------------------");

		boost::mutex mutex;
		MutexTestA testA(&mutex);
		boost::thread boostThread(testA);

		DWORD junk;
		HANDLE winThread = ::CreateThread(NULL, 0, MutexTestB, &mutex, 0,
&junk);
	
		boostThread.join();
		// todo: howto wait for winThread?	
	}
	else {
		puts("usage: boost-win [boostcs]");
		puts("options:");
		puts("   cs - see if boost and win threads can both honor a
CRITICAL_SECTION");

		return 1;
	}
	
	return 0;
}

-------------- next part --------------
A non-text attachment was scrubbed...
Name: boost-win.cpp.tar.gz
Type: application/x-compressed-tar
Size: 1295 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20060428/3898b105/boost-win.cpp.tar.bin


More information about the wine-devel mailing list