Notes
Slide Show
Outline
1
Active Object
  • Object-Oriented Threading
  • Bartosz Milewski
2
Analogy
  • Assembly-line model
    • Next operation is executed after the previous one has completed
  • Outsourcing model (independent contractor)
    • Specify the job, give a go-ahead
    • Continue with your own work as if nothing happened
3
Interaction
  • Establish secret language
    • Share data back and forth
    • Be prepared for interruptions
    • Poll
    • Wait for completion
  • Accept the result
  • Kill the contractor?!


4
Conceptual Model
  • Each thread as a separate processor
  • Separate stacks of execution (local variables, function arguments)
  • Shared global memory
    • Reads and writes arbitrarily interleaved
  • Synchronization primitives
    • Runtime/Compiler supported
    • Operating system
5
The Spawning
  • Hire a contractor
    • Create a thread of execution
  • Give him a job
    • Give it a function to execute
  • Specify the details of the job
    • Pass a void pointer (yeah, lame!)
  • Give a go-ahead
    • Start thread
  • (Worry about the rest later)
6
Windows Thread API
  • New thread executes thread procedure
  • Initial data passed through void pointer
7
Thread Handle
8
Thread Auto Handle
9
The Constructor & The Killer
10
Template Anyone?
  • Raw C API: generic function pointer and generic argument
  • Modern C++: template parameterized by function type and argument types
  • Seems like a good idea at first
  • But is Thread a good abstraction?
11
In Search of Abstraction
  • A thread is created
    • To execute a single job
    • To become a server for jobs
  • A job may require arguments and return values
  • A server requires a queue of jobs
  • Shared data, synchronization objects
  • These are all data structures!
12
Objects to the Rescue
  • Create an active object with:
    • Initial data (arguments)
    • Shared data
    • Synchronization primitives
    • Private data
  • Start it
  • Interact with it (actively and passively)
  • Delete it
13
Where Does the Thread Go?
  • The thread is created deep inside the constructor of ActiveObject
  • The this pointer is passed to the thread
  • Private static method of ActiveObject serves as Thread Procedure
  • All the casting is hidden inside ActiveObject which is a library class
14
What is Active Object?
  • A framework
    • The client implements pure virtual methods (in particular, Run)
    • The framework calls them
  • Static ThreadEntry called with the this pointer (the handler function pattern?)
15
Construction
  • Note: thread is born suspended
    • Somebody must start it
16
Example
  • Windows application listing a directory
    • Active object Lister: lists files asynchronously, passes partial results to Accumulator
    • Active object Accumulator: accumulates listing from Lister, merges partial results, passes them to the application
    • Application: displays the listing dynamically
17
Example of Run
  • Note the checking of IsDying after every wakeup
  • To kill the thread, set the dying flag and release the event
  • This thread may have to complete MergeChunks before it dies
  • Depositing into external sink (the application) may fault—use critical section
18
Not so Easy
  • How to start a thread? Who calls this?
19
Destructor is not a killer!
  • Naïve solution: call Kill inside the destructor and wait for it to finish
  • Kill must not be called inside the ActiveObject destructor
    • Never call virtual functions from inside a destructor

20
Blocking Again?
  • Who deletes the Active Object?
    • Cannot be deleted before the thread is done running
    • Waiting for the thread to terminate defeats the purpose of multithreading
21
Let the Thread Worry!
  • Waiting for the tread to finish before deleting the Active Object not good!
  • Forget about the Active Object after you’re done with it
  • Let the dying thread delete it
  • Thread must own the object
22
Ownership
  • The thread runs
    • To completion, or
    • Until it’s killed
  • Waits to be killed (if it has run to completion)
  • Deletes the Active Object
23
Synchronized Killing
  • Note: IsDying is to be tested by the client inside Run
24
Too Error Prone!
  • Remember to start the thread
  • Remember to kill the thread
  • Solution: use a smart pointer object
25
Example of auto_active Lister
  • Example: Lister, lists files in a directory
26
Run Lister::Run
27
auto_active
28
Additional Methods
29
Synchronizing Down
  • The client of ActiveObject wants to access data
  • Add critical section to ActiveObject
  • Expose locked methods to client
30
Synchronizing Up
  • ActiveObject wants to notify/return data to the client
  • Expose the Sink interface to ActiveObject
  • Example
    • Client Lister, calls _sink->DataReady
    • Object Acumulator implements Sink interface (see previous slide)
31
The Windows Thread
  • Main application thread loops:
    • Blocks in GetMessage
    • Calls DispatchMessage
    • Calls Windows procedure
  • While WinProc executes, app is not responding
  • WinProc message handlers must execute quickly
32
Windows Sink
  • Top-level ActiveObject passes data to its sink
    • Data to be displayed by main thread
    • Sink implementation calls PostMessage
    • Message queue—synchronized access
33
Responsive App Pattern
  • Embed auto_active in the Controller object
  • Let Controller implement DataSink interface. DataReady should post a message, the Controller should handle this message
  • Initialize auto_active with an appropriate ActiveObject. Give ActiveObject a pointer to Controller as DataSink
  • When done, reset the auto_active