21
Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Embed Size (px)

Citation preview

Page 1: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Win32 ProgrammingLesson 13: Thread Pooling(Wow, Java is good for something…)

Page 2: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Where are we? We know everything there is to know about

threads in Windows Not But there’s only another 2 lectures on this Introduce a simplifying idea: thread pooling

Page 3: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

What is Thread Pooling Thread pooling allows us to let the OS create and

destroy threads for us Each worker thread gets woken up when there’s a

job to do The OS decides whether to create a new thread or

wait for an existing one Caveat emptor: setting up a thread pool is quite

expensive – the wins come on continued reuse

Page 4: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Scenario 1: Call functions asynchronously Very common problem Example: a server which spawns a worker

thread to serve a particular client In this case, the function

QueueUserWorkItem is quite handy

Page 5: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

QueueUserWorkItem BOOL QueueUserWorkItem(

   PTHREAD_START_ROUTINE pfnCallback,    PVOID pvContext,    ULONG dwFlags); 

Queues a thread work item and returns immediately Callback function must have the form:

DWORD WINAPI WorkItemFunc(PVOID pvContext); Note the return code is ignored

Page 6: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

What do you Notice? No call to _beginthreadex or CreateThread The system creates and manages threads for

you Can gain efficiency as threads are re-used, not

recreated for each new work item (system spends less time creating and destroying threads)

Page 7: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Beware Because the system is managing the threads,

you need to be very careful if you put your thread to sleep and wait for an asynchronous request (like IO) Set dwFlags to WT_EXECUTEINIOTHREAD Need to help the system decide that a thread may

take a long time to complete (so set WT_EXECUTELONGFUNCTION)

Page 8: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Call Functions at Timed Intervals Create a queue:

HANDLE CreateTimerQueue(); Create timers in the queue:

BOOL CreateTimerQueueTimer(    PHANDLE phNewTimer,     HANDLE hTimerQueue,    WAITORTIMERCALLBACK pfnCallback,     PVOID pvContext,     DWORD dwDueTime,     DWORD dwPeriod,     ULONG dwFlags); 

Page 9: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Timer work function Must be of form:

VOID WINAPI WaitOrTimerCallback(    PVOID pvContext,     BOOL fTimerOrWaitFired);  fTimerOrWaitFired is always TRUE

WT_EXECUTEINTIMERTHREAD is interesting Executes in timer thread Very dangerous, but useful when used correctly

Page 10: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Deleting Timers Must do this even for one-shot timers

BOOL DeleteTimerQueueTimer(    HANDLE hTimerQueue,     HANDLE hTimer,    HANDLE hCompletionEvent); 

Blocks until completion if hCompletionEvent is INVALID_HANDLE_VALUE

Page 11: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

But… Can pass NULL to the timer for

hCompletionEvent In this case, the Timer is deleted ASAP, but you

won’t know when Finally, can pass an Event Kernel Object

Sets event when the timer is actually deleted

Page 12: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Scenario 3: KO Signaled Lots of applications spawn a thread to wait on

completion of a Kernel Object Wasteful of resources – if this happens a lot better to

use a thread pool CPU Intensive operation when you create/destroy threads Still better than a process

Page 13: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

API BOOL RegisterWaitForSingleObject(

   PHANDLE phNewWaitObject,     HANDLE hObject,    WAITORTIMERCALLBACK pfnCallback,     PVOID pvContext,    ULONG dwMilliseconds,    ULONG dwFlags); 

hObject is the object to wait on Time is between 0 and INFINITE

Page 14: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Unregistering a Wait If the desired object gets signaled multiple times, the

Wait object will be woken up multiple times Unless of course you set WT_EXECUTEONLYONCE

But, you must still call: BOOL UnregisterWaitEx(

   HANDLE hWaitHandle,    HANDLE hCompletionEvent); 

Page 15: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Call Functions on I/O Common scenario

Wish to call a function when an asynchronous I/O event completes

You may want to look up “I/O Completion Ports”

Page 16: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Function Format BOOL BindIoCompletionCallback(

   HANDLE hDevice,    POVERLAPPED_COMPLETION_ROUTINE pfnCallback,    ULONG dwFlags); 

Callback function of form: VOID WINAPI OverlappedCompletionRoutine(

   DWORD dwErrorCode,    DWORD dwNumberOfBytesTransferred,    POVERLAPPED pOverlapped); 

Page 17: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Fibers The idea came when MS thought about

application developers porting applications from UNIX to Windows

UNIX lacks the same threading functionality that Windows has, and so implements “threading” quite differently

Fibers make port a lot easier… but they are no substitute for native Windows threads

Page 18: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

A what? Every thread contains one or more fibers As far as the Kernel is concerned, each thread

gets preemptively scheduled The thread decides which fiber to execute Only one fiber gets executed at a time

Page 19: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

API First, must convert the existing thread to a Fiber:

PVOID ConvertThreadToFiber(PVOID pvParam); This function allocates memory (about 200 bytes) for the

fiber's execution context which contains: A user-defined value that is initialized to the value passed to

ConvertThreadToFiber's pvParam argument The head of a structured exception handling chain The top and bottom memory addresses of the fiber's stack (When

you convert a thread to a fiber, this is also the thread's stack.) Various CPU registers, including a stack pointer, an instruction

pointer, and others

Page 20: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Create Additional Fibers No point ever converting a thread if you don’t

do this! PVOID CreateFiber(

   DWORD dwStackSize,     PFIBER_START_ROUTINE pfnStartAddress,    PVOID pvParam);

Function API is: VOID WINAPI FiberFunc(PVOID pvParam);

Page 21: Win32 Programming Lesson 13: Thread Pooling (Wow, Java is good for something…)

Executing Fibers To make the new fiber execute you call:

VOID SwitchToFiber(PVOID pvFiberExecutionContext);

This stores needed information on the current fiber and sends processing to the new one

It’s the only way a fiber can get CPU time Destroy using DeleteFiber