Page 1 of 1

Multi-threading on Multi-processors creating a thread for each processor Rate Topic: ***** 1 Votes

#1 bizzehdee  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 5
  • View blog
  • Posts: 54
  • Joined: 06-April 08

Post icon  Posted 17 May 2008 - 03:01 PM

this piece of code was writen to do a large amount of data processing, and i wanted to take full advantage of multi-core/multi-processor machines as much as possible.

first, you need to know how many processors/cores are available to you.

this is done with the GetNumCPUs() function.
DWORD_PTR GetNumCPUs() {
  SYSTEM_INFO m_si = {0, };
  GetSystemInfo(&m_si);
  return (DWORD_PTR)m_si.dwNumberOfProcessors;
}

this pretty much returns the number of available cores (note: single cpu's that are hyperthreading enabled also show as 2 cpu's).

once you have the number of processor, you can then create a loop that will cycle through each processor.
DWORD_PTR c = GetNumCPUs();
for(DWORD_PTR i = 0; i < c; i++) {

}


this will simply cycle through a for loop at least once (because you will always have 1 processor) upto the number of processors/cores you have.

now, if you want to actualy DO something with this loop and your processors/cores, you will need to create some threads for them. each thread will run independantly of the others within the application (though, they can interact, this is not the purpous of this tutorial).

first you will need to create your thread procedure.
DWORD_PTR WINAPI threadMain(void* p) {

  return 0;
}


this is a simple "do nothing" thread that you can fill in later.

next, you will need to create the threads.
m_threads = new HANDLE[c]; //needed to store the handles of your threads
DWORD_PTR c = GetNumCPUs();
for(DWORD_PTR i = 0; i < c; i++) {
  DWORD_PTR m_id = 0; //mostly useless, just to complete the CreateThread function

  //create the thread and store its handle for later, and pass the processor count to the thread
  m_threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadMain, (LPVOID)i, NULL, &m_id);
}


now you have a thread running for each cpu within the current system (ie, on mine it would be 2, on a quad core, it would be 4, on a single core system, it would be 1), but we havnt assigned them to any particular cpu or core yet. the processor its self, and the operating system will generaly do this for you automaticaly, but wont split them up equaly, they will just offload them to the processors/cores that are least being utalized at the time.

so now, we will assign the threads to each processor/core our selfs.
m_threads = new HANDLE[c]; //needed to store the handles of your threads
DWORD_PTR c = GetNumCPUs();
for(DWORD_PTR i = 0; i < c; i++) {
  DWORD_PTR m_id = 0; //mostly useless, just to complete the CreateThread function
  DWORD_PTR m_mask = 1 << i; //creates a mask of the processor/core number

  //create the thread and store its handle for later, and pass the processor count to the thread
  m_threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadMain, (LPVOID)i, NULL, &m_id);
  SetThreadAffinityMask(m_threads[i], m_mask); //assigns the thread to a processor/core

  wprintf(L"Creating Thread %d (0x%08x) Assigning to CPU 0x%08x\r\n", i, (LONG_PTR)m_threads[i], m_mask); //just so we can see whats going on as it goes on (if your not using unicode, you should use printf here and not wprintf.
}


and thats it, put it together, and you have an application that can be far more effective at doing almost anything as long as you know what your doing.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

HANDLE *m_threads = NULL;
DWORD_PTR WINAPI threadMain(void* p);

DWORD_PTR GetNumCPUs() {
  SYSTEM_INFO m_si = {0, };
  GetSystemInfo(&m_si);
  return (DWORD_PTR)m_si.dwNumberOfProcessors;
}

int wmain(int argc, wchar_t **args) {
  DWORD_PTR c = GetNumCPUs();

  m_threads = new HANDLE[c];

  for(DWORD_PTR i = 0; i < c; i++) {
	DWORD_PTR m_id = 0;
	DWORD_PTR m_mask = 1 << i;

	m_threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadMain, (LPVOID)i, NULL, &m_id);
	SetThreadAffinityMask(m_threads[i], m_mask);

	wprintf(L"Creating Thread %d (0x%08x) Assigning to CPU 0x%08x\r\n", i, (LONG_PTR)m_threads[i], m_mask);
  }

  return 0;
}

DWORD_PTR WINAPI threadMain(void* p) {

  return 0;
}


Research: CreateThread | SetThreadAffinityMask | GetSystemInfo

Is This A Good Question/Topic? 1
  • +

Replies To: Multi-threading on Multi-processors

#2 themadme  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 19-January 09

Posted 19 January 2009 - 05:39 PM

By any chances is there a way to find out if a core is hyper threaded or not?
Was This Post Helpful? 0
  • +
  • -

#3 oscode  Icon User is offline

  • D.I.C Regular

Reputation: 109
  • View blog
  • Posts: 257
  • Joined: 24-October 10

Posted 19 July 2011 - 04:05 AM

You shouldn't use CreateThread (unless it's Windows CE, as it works correctly) along with the standard C++ library. Instead, you should use _beginthread/ex, see:
http://stackoverflow...-createthread-c

I'd recommend using std::vector<HANDLE> threads(GetNumCPUs()); over unnecessary manual allocations.

Thanks for the tutorial, perhaps one on thread safety next? :)
Was This Post Helpful? 0
  • +
  • -

#4 Ricky65  Icon User is offline

  • D.I.C Head

Reputation: 38
  • View blog
  • Posts: 115
  • Joined: 03-June 10

Posted 13 August 2011 - 03:12 AM

The problem with using the CreateThread Win32 API is that it only works on Windows and is not portable. It's much better to use a portable library such as boost::thread or if you have a C++0x compiler std::thread is even better.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1