Threading and P/Invoke

cavalcadejewelΛογισμικό & κατασκευή λογ/κού

18 Νοε 2013 (πριν από 3 χρόνια και 6 μήνες)

81 εμφανίσεις

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 cleanup

using(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 example

public 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 lock

public 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);


}


}

}


P/Invoke Callbacks


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

Managed Code

.NET Application

Call passes pointer to
callback function

Implementation of callback
function

Unmanaged Code

DLL

DLL function

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