programming4us
programming4us
ENTERPRISE

.NET Micro Framework : Multithreading and Synchronization

10/14/2010 3:39:52 PM
In .NET, parallel program execution is possible using multiple threads. A thread is an independent code path that can run parallel to other threads. With threads, you can process several tasks simultaneously.

Threads are more lightweight than processes; that means the system can switch between threads faster. In the .NET Micro Framework, only one application (process) can run at a time, so for parallel program execution with the .NET Micro Framework, only threads are applicable.

A .NET application starts as an individual thread, the main thread. The main thread is created automatically by the runtime environment. An application can consist of several threads, and the different threads can access common data. Therefore, you need to synchronize access to shared resources from different threads.

Threads run on single-processor systems, and like all platforms for the .NET Micro Framework, are not actually parallel, but the runtime environment alternates among threads to provide each thread processor time. You can control the assignment of computing time more precisely by setting the thread priority of each thread. Thus important tasks can be processed faster than, for example, some monitoring in the background. The thread priority indicates how much processor time a thread gets compared to other threads.

You can find a very detailed description of multithreading and synchronization with the .NET Framework at www.albahari.com/threading/threading.pdf.


1. Using Threads

Threads are programmed in the .NET Micro Framework in a way that's similar to the full .NET Framework. Of course, the functionality has been reduced to a minimum. Nevertheless, the most necessary methods and properties are available. A thread is represented by the System.Threading.Thread class, as shown in Listing 9-1.

Example 1. The System.Threading.Thread Class
using System;

namespace System.Threading
{
public sealed class Thread
{
public Thread(ThreadStart start);

public static Thread CurrentThread { get; }
public bool IsAlive { get; }
public ThreadPriority Priority { get; set; }
public ThreadState ThreadState { get; }

public void Abort();
public static AppDomain GetDomain();
public void Join();
public bool Join(int millisecondsTimeout);
public bool Join(TimeSpan timeout);
public void Resume();
public static void Sleep(int millisecondsTimeout);
public void Start();
public void Suspend();
}
}

NOTE

The static Sleep method of the Thread class has already been used in several sample programs. You should consider that the thread from which the method is called is always paused. That means calling the Sleep method from the main thread will pause the main thread, and calling the method from code that is executed from a background thread will pause the background thread.

Now you will learn how to create and start a thread. Listing 9-2 shows how this is done. You need to pass a pointer to a parameterless method containing the task you want to process with the constructor. That method is called a callback, or thread, method and can be static or belong to an object instance. Afterward, you need to start the thread with its Start method. The thread is terminated as soon as the thread worker method is done.

Example 2. Creating and Starting a Thread
public class Program
{
public static void Main()
{
Thread myThread = new Thread(MyThreadMethod);
myThread.Start();
//main thread continues here
...
}

private static void MyThreadMethod()
{
//do some work here
}
}

It is possible to wait for completion or termination of another thread before moving on with the application, which is done by calling the Join method of the thread you want to wait for. There are three overloads of this method (see Listing 9-1): the parameterless version blocks and waits infinitely for the termination. The other two variants expect a timeout parameter indicating the maximum waiting time. The methods return true if the thread was terminated in the specified time and false if the thread is still alive.

2. Synchronization

Conflicts can occur any time several threads access shared resources, so you need to synchronize access to shared data.

The interrupt method of an interrupt port and the timer method of a timer are each called in the context of a separate thread. Access to resources within these methods has to be synchronized as well.


The .NET Framework provides several possibilities for synchronization. A simple way to prevent a method from being executed by several threads at the same time is to mark the method as synchronized by adding the following attribute:

[MethodImpl(MethodImplOptions.Synchronized)]
private void MySynchronizedMethod()
{
//...
}

The synchronized method will be locked for other threads as soon as it is entered by a thread. Other threads trying to execute this method are blocked until the locking thread returns from the method.

In the preceding example, the method will be locked during the entire time a thread is executing it, even if critical resources are accessed only in a small part of the entire method. A better approach is to lock a method only during the execution of critical parts. That type of access to objects can be synchronized with the MonitorSystem.Threading namespace: class from the

private static MyThreadMethod1()
{
...
Monitor.Enter(myCriticalObject);
//access shared data here
Monitor.Exit(myCriticalObject);
...
}

private static MyThreadMethod2()
{
...
Monitor.Enter(myCriticalObject);
//access shared data here
Monitor.Exit(myCriticalObject);
...
}

Both thread methods are executed at the same time, and both access the same data at the same time. After the Enter method is called, other threads reaching EnterExit method is called by the locking thread. You should place the Exit call within the finally block of an exception handler, so the lock is released in case of an exception so that other threads will not be blocked forever. To simplify this situation, you can use the C# keyword lock. will be blocked until the

lock(myCriticalObject)
{
//access data
}

The preceding construct is compiled by the C# compiler to the following code:

try
{
Monitor.Enter(myCriticalObject);
//access data
}
catch(Exception)
{
Monitor.Exit(myCriticalObject);
}

The Interlocked class from the System.Threading namespace offers the possibility to increment or decrement by one an integer variable or swap the value of two variables as an atomic operation that cannot be interrupted. An atomic operation is always executed completely and, therefore, will not be interrupted by another thread during execution.

3. Events

In addition to using the Monitor class or the lock construct to synchronize access to shared resources, you can use events. Events allow you to signal other waiting threads that a certain action, like the completion of a task, has occurred. You can also wait for multiple events.

For synchronization with events, there are the two classes: ManualResetEvent and AutoResetEvent. These classes differ only in the fact that you must reset the status of a ManualResetEvent manually after signaling an event. Both classes are in the System.Threading namespace, and both inherit from the abstract WaitHandle class, which possesses the methods represented in Listing 9-3. The documentation of the .NET Micro Framework SDK is not correct and describes only two members of this class.

Example 3. The System.Threading.WaitHandle Base Class of ManualResetEvent and AutoResetEvent
namespace System.Threading
{
public abstract class WaitHandle : MarshalByRefObject
{
public const int WaitTimeout = 258;

protected WaitHandle();

public static bool WaitAll(WaitHandle[] waitHandles);
public static bool WaitAll(WaitHandle[] waitHandles,
int millisecondsTimeout, bool exitContext);
public static int WaitAny(WaitHandle[] waitHandles);
public static int WaitAny(WaitHandle[] waitHandles,
int millisecondsTimeout, bool exitContext);
public virtual bool WaitOne();
public virtual bool WaitOne(int millisecondsTimeout, bool exitContext);
}
}


The two event classes, ManualResetEvent and AutoResetEvent, possess the methods Set and Reset. When creating an instance of an event class, you can pass the initial state to the constructor. After an AutoResetEvent object is set, it remains signaled until another thread waits for this event (at which time, it resets automatically).

In Listing 4, you can see how to use the AutoResetEvent class. The main thread creates a new thread, starts it, and waits until the created thread signals this event.

Example 4. Using AutoResetEvent
using System.Threading;
using Microsoft.SPOT;

namespace ThreadingEventSample
{
public class Program
{
private static AutoResetEvent ev = new AutoResetEvent(false);

static void Main()
{
Thread thr = new Thread(WaitForEvent);
thr.Start();

Debug.Print("Waiting...");
ev.WaitOne(); //waiting for notification
Debug.Print("Notified");
}

private static void WaitForEvent()
{
Thread.Sleep(1000); //sleep to simulate doing something
ev.Set(); //wake up other thread
}
}
}

Other  
 
Video
PS4 game trailer XBox One game trailer
WiiU game trailer 3ds game trailer
Top 10 Video Game
-   Call Of Duty: Black Ops III [PS4/XOne/PC] Zombies - Shadows of Evil Trailer
-   No Time To Explain [XOne/PC] Multiplayer Trailer
-   Bierzerkers [PC] Early Access Trailer
-   Downward [PC] Kickstarter Trailer
-   Grip [PS4/PC] Trailer
-   Hitman [PS4/XOne/PC] Debut Trailer
-   Gears of War: Ultimate Edition [XOne] Recreating the Cinematics Trailer
-   Gravity Falls: Legend of the Gnome Gemulets [3DS] Debut Trailer
-   Street Fighter V [PS4/PC] Ken Trailer
-   Doctor Who | Series 9 Teaser Trailer
-   Transformers: Devastation | Gameplay Trailer (SDCC 2015)
-   Tom Clancy's Rainbow Six Siege | Inside Rainbow #3 – The GIGN Unit
-   Final Fantasy XIV: A Realm Reborn 'Alexander' Video
-   SirVival Trailer
-   Blood Bowl II [PS4/XOne/PC] Overview Trailer
Game of War | Kate Upton Commercial
programming4us
 
 
programming4us