330 likes | 443 Views
Threading and P/Invoke. Tom Roeder CS215 2006fa. Finalization. Recall C++ destructors: ~MyClass() { // cleanup } called when object is deleted does cleanup for this object Don’t do this in C# (or Java) similar construct exists but only called on GC no guarantees when. Finalization.
E N D
Threading and P/Invoke Tom Roeder CS215 2006fa
Finalization • Recall C++ destructors:~MyClass() { // cleanup} • called when object is deleted • does cleanup for this object • Don’t do this in C# (or Java) • similar construct exists • but only called on GC • no guarantees when
Finalization • More common idiom:public void Finalize() { base.Finalize(); Dispose(false);} • maybe needed for unmanaged resources • slows down GC significantly • Finalization in GC: • when object with Finalize method created • add to Finalization Queue • when about to be GC’ed, add to Freachable Queue
Finalization images from MSDN Nov 2000
IDisposable and using • Idea for common cleanupusing(T t = new T()) { // do work with t} // t.Dispose is called by runtime • IDispose provides one method: void Dispose() • must provide finalizer, since must be called • when called from finalizer, don’t undo managed obj • often add private void Dispose(bool) • using calls Dispose automatically • used in class libraries, eg. for Socket
Weak References • Sometimes want to keep references but not cause the GC to wait • MyClass c = new MyClass();WeakReference wr = new WeakReference(c); • Now c can be collected • wr will return null if referenced after c collected • but to truly access the object, we get a strong ref • this is the Target property • Why? • Useful for large objects • infrequently accessed • nice to have but can be regenerated
Resurrection • Imagine assigning this to global in finalizer • object is now reachable again! • called “resurrection” • if finalizer already called, access unpredictable • Should not do this • but, if do, may want to reject accesses in methods • what would this finalize code do:someObj = this;System.GC.ReRegisterForFinalize()
System.GC • Can control the behavior of GC • not recommend in general • sometimes useful to give hints • Some methods: • Add/RemoveMemoryPressure • ReRegisterFor/SuppressFinalize • WaitForPendingFinalizers • Collect
Memory Profiles • Good • lots of small short-lived objects • or few but long-lived ones • few links between old and new objects • Bad • frequently create long-lived objects • create many objects that live a long but fixed amount of time
unsafe mode • Sometimes need access to pointers • use unsafe modifier:unsafe public void Method(out int* pi) { int i = 10; fixed(int* pj = &i) { pi = pj; }} • what is wrong with this method? • unsafe modifier works a method modifier • or as a keyword for blocks
unsafe mode - Pointer details • Can only refer to “unmanaged” types • or enums • or structs composed of unmanaged types • Not a subclass of object • void* exists, but no arithmetic allowed • boxing/unboxing does not work • stackalloc gets memory from the stack
unsafe mode • Cannot be executed in untrusted context • security requirement: so can’t change memory • eg. avoid stack smashing attacks • pointer types • cannot refer to a reference • cannot refer to a struct that contains references • int* pi, pj; // NOT int *pi, *pj;
Threading • Threading provides concurrent execution • Even useful on multiprocessor • As opposed to “sequential” execution • Comes at cost of overhead • Can be dangerous • For examplepublic int Increment(ref int x) { return ++x; } • What happens when called by two threads? • How to fix?
Threading • How to create a Thread • Create a new Thread instance with delegate • Type: public delegate void ThreadStart(); • Call Start method • Let’s do an example on the board • Thread will be scheduled when possible • on SMP, may actually have many threads at once • on UP, still may be useful when blocked • as in UI, networking code, dealing with drivers
Threading • Need synchronization primitives • Way to ensure that only one thread executes code in a region at once • Called “critical section” • C# provides (mostly in System.Threading) • lock statement • Monitor class • Interrupt • several others (see Birrell’s paper or MSDN)
Threading model: lock • Basic idea: each object has a lockpublic int Increment(ref int x) {lock(this) return ++x;} • lock prevents more than one thread from entering • forces sequential order • What should we lock on? • for instance variables: this • for globals and statics: typeof(container) • something that will be same for all threads that access this shared memory
Threading model: Monitor • Monitors provide synchronization construct • entry waits on a queue • waiting lets a new thread enter • Monitor.Enter and Monitor.Exit • same semantics as the lock construct • Why do we need both? • Gets a lock on the object • Cannot be used on value types: why not?
Threading model: Monitor • Methods • Monitor.Enter/Monitor.Exit • enter/exit the monitor for a given object • Monitor.Wait • wait on a given object • must be inside a monitor for that object • signal-delayed semantics • Monitor.Pulse/Monitor.PulseAll • some thread(s) can be released to try the monitor
Threading model: Interrupt • Sometimes need to wake up a thread • eg. if UI cancelled • eg. if event no longer needed • Standard OO way: exceptions • Interrupt causes thread to throw ThreadInterruptedException • only on Wait or Sleep • Allows cleanup of invariants
Other synchro classes • Abort • throws exception immediately • difficult to clean up: Why? • usually too draconian • Mutex and other synchronization • good for interacting with Windows • but stick with lock and Monitor, normally • ReaderWriter Locks • not clear exactly what semantics they implement
Threading model: ThreadPool • Instead of explicitly creating threads • create a pool • pass delegates to worker threads • enqueued in pool • QueueUserWorkItem • takes a WaitCallback delegate • Good for large amounts of parallel work • eg. N-Body problem • automatically scales to number of processors • “embarrasingly parallel” problems
Threading Conclusions • Standard monitor semantics • as in Java • useful constructions • OS synchronization exposed • native ThreadPool • Really only need • lock • Monitor
P/Invoke • Use special attributes to make system calls • eg.[DllImport(“kernel32”)]static extern int GetProcessHeap(); • calls to function in C library • problems for C++ • name mangling: doesn’t match • General problem of COM/.NET interop • why does this matter?
COM Interoperability • Need metadata • generated from TypeLib • Can then use COM class like .NET class • even though major differences in models • eg. threading, registration, inheritance • useful for backwards compatibility • Can bind early or late to class • either we know its type at compile time or not
Calling a COM Server namespace CallingCOMServer { using System; using COMServerLib; public class DotNET_COMClient {... public static int Main(string[] args) { MyCOMServer myS = new MyCOMServer(); return (myS.Add (17,4)); } } };
Late-Bound Activation • Use Reflection to get the type of the class • ProgID / ClassID: looked up in registry • gives type of COM object • Can instantiate instance and call methods • uses InvokeMethod to call methods • don’t have as strong type information here • COM object wrapped by __ComObject • can sometimes use as to get better info
Late-Bound namespace LateBoundClient { using System.Reflection; ... Type typ; Object obj; Object[] prms = new Object[2]; int r; typ = Type.GetTypeFromProgID(„MyLib.MyServer"); obj = Activator.CreateInstance(typ); prms[0] = 10; prms[1] = 150; r = (int)typ.InvokeMember(„aMethod", BindingFlags.InvokeMethod, null, obj, prms); ... }
.NET from COM • Needs to be public with public methods • Need to register a wrapper: use RegAsm tool • provides ProgID/ClassID information for registry • necessary for COM integration • Metadata must be converted to TypeLibrary • Have same early- and late-bound activation • early: by name • late: by ProgID/ClassID
Platform from .NET • Calling static functions in DLLs • P/Invoke provides services • Locates implementing DLL • Loads DLL • Finds function address • Fuzzy name matching algorithm • Pushes arguments on stack • Performs marshalling • Enables pre-emptive garbage collection • Transfers control to unmanaged code
P/Invoke Example namespace HelloWorld{ using System; class MyClass { [dllimport(“user32.dll”, CharSet=CharSet.Ansi)] static extern int MessageBox(int h, string m, string c, int t); public static int Main() { return MessageBox(0, "Hello World!", "Caption", 0); } }}
Unmanaged code can call back to managed code Unmanaged parameter is function pointer Must supply parameter as delegate P/Invoke creates callback thunk Passes address of thunk as callback parameter Unmanaged Code Managed Code .NET Application DLL Call passes pointer to callback function DLL function Implementation of callback function P/Invoke Callbacks
Callback Example public class EnumReport { public bool Report(int hwnd, int lParam) { // report the window handle Console.Write("Window handle is "); Console.WriteLine(hwnd); return true; }}; public class SampleClass{ delegate bool CallBack(int hwnd, int lParam); [DllImport("user32")] static extern int EnumWindows(CallBack x, int y); public static void Main() { EnumReport er = new EnumReport(); CallBack myCallBack = new CallBack(er.Report); EnumWindows(myCallBack, 0); }}
Managed Extensions for C++ • Allows C++ code to be managed by GC/CLR • compile with /clr: It Just Works • generates MSIL from C++ • contains, eg • __gc, __box, __typeof, __interface, __property • #pragma managed/unmanaged • Very useful for native access to C++ libraries • build a “managed wrapper” • Partial conversion to managed code