Jump to content

  • Log In with Google      Sign In   
  • Create Account






Setting Thread Affinity on Windows in D

Posted by Aldacron, in D 03 April 2012 · 1,429 views

When working with D's standard library, it is sometimes necessary to work around missing declarations in the core.sys.windows.windows module. It's a fairly big module as is, but it isn't all-inclusive. If you are doing any heavy-duty Windows development, you'll likely want a third-party Win32 API binding. But if you just need to call a function or two, that's overkill.

A good example of this is the need to lock the timing thread to one core when dealing with the Windows timer on a multi-core machine. This is a well-known solution to the problem of erratic timing results returned by QueryPerformanceCounter. If you are using a library like SDL, which uses QPC under the hood for its timing calls, this is something you ought to consider. Unfortunately, Phobos is currently missing declarations for a couple of function calls and one type that you need to lock the timing thread down.

For many cases, this can be overcome by adding the appropriate declarations where you need them. In other cases, you'll find (particularly when using DMD) that the Win32 import libraries that ship with the compiler are outdated. In that case, you'll either need to generate them yourself or load the function symbols manually via LoadLibrary and friends. Luckily, for setting the thread affinity the solution is easy. Here's a complete example, ripped right out of the module where I use it.

version(Windows)
{
	private
	{
		import core.sys.windows.windows;
		import std.windows.syserror;

	    // Declarations missing from the windows module.
		alias size_t DWORD_PTR;
		extern(Windows)
		{
			DWORD SetThreadAffinityMask(HANDLE,DWORD);
			BOOL GetProcessAffinityMask(HANDLE,DWORD_PTR*,DWORD_PTR*);
		}

		void setThreadAffinity()
		{
			void doThrow(string msg)
			{
				auto err = GetLastError();
				throw new Exception(msg ~ sysErrorString(err));
			}

			DWORD_PTR procMask, sysMask;
			if(!GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask))
				doThrow("GetProcessAffinityMask failure: ");

			DWORD_PTR mask = 1;
			if(mask & procMask)
			{
				if(!SetThreadAffinityMask(GetCurrentThread(), mask))
					doThrow("SetThreadAffinityMask failure: ");
			}
			else
			{
				throw new Exception("Unexpected affinity mask mismatch.");
			}
		}
	}
}


Drop this into module or class scope and add the following to an init method somewhere in the same module (or another module if you move setThreadAffinity out of the private block).

version(Windows) setThreadAffinity();


Notice also that I imported std.windows.syserror, which exposes the sysErrorString function. I'm sure I wasn't the only one who overlooked that module. After years of using D, I only noticed it recently. If you're going to be making Win32 API calls, it will come in handy.




September 2014 »

S M T W T F S
  1 23456
78910111213
14151617181920
21222324252627
282930    

Recent Entries

Recent Comments

PARTNERS