Creating Multithreaded Applications


Multithreading allows an application or service to use the multithreading capability of the underlying operating system to develop applications that can distribute the amount of work into a set of parallel individual tasks (or threads). Multithreading applications are typically used to serve multiple user requests at one time. Combined with the use of networking or sockets, multithreading applications were created primarily to develop back-end server-side engines.

DO YOU HAVE TO ALWAYS USE THREADS EXPLICITLY FOR MULTIPROCESSING APPLICATIONS?

The use of explicit multithreading today is considered quite a low-level interface for implementing concurrent applications in .NET applications. The capabilities provided by Remote Objects and Enterprise Services (which implicitly utilize the threading concepts internally) also provide constructs for creating concurrent, scalable services. However, these services often abstract the inner details of threading from the developer.


At the core level, concurrent application development is supported by the System.Threading namespace. Key classes in the namespace include the following:

  • Monitor ” Provides synchronization access to objects

  • Mutex ” A primitive that can be used for interprocess synchronization

  • Thread ” Basic class for creating a new thread

  • ThreadPool ” Provides a pool of threads

  • Timer ” Provides the capability to execute a method at a particular interval

  • ThreadState ” Enumeration that represents the state of a Thread (Unstarted, Running, WaitSleepJoin, SuspendRequested, Suspended, Stopped)

To understand the use of threading in applications, you can create an inventory check application (shown in Listing 4.13) that looks at the inventory of an order or item with two suppliers and outputs the status of the inventory with both the suppliers. To demonstrate the delay that occurs while inventory is being looked up (that is the reason for multithreading here), you'll configure the two supplier threads to sleep for 5 and 10 seconds, respectively, so that you can see the first supplier process completing earlier than the second supplier process.

Listing 4.13 Applying Multithreading
 using System; using System.Threading; class Threads {    public static void Main()    {       String order = "ABC Computer";       FirstSupplier first = new FirstSupplier(order);       SecondSupplier second = new SecondSupplier(order);       Thread t2 = new Thread(new ThreadStart(second.CheckInventory));       t2.Start();       Thread t1 = new Thread(new ThreadStart(first.CheckInventory));       t1.Start();       t1.Join();       t2.Join();       if (first.availability)          Console.WriteLine("1st Supplier has +ve Inventory");       else          Console.WriteLine("1st Supplier has -ve Inventory");       if (second.availability)          Console.WriteLine("2nd Supplier has +ve Inventory");       else          Console.WriteLine("2nd Supplier has -ve Inventory");    } } class FirstSupplier {    public string order;    public bool availability;    public FirstSupplier(String order)    {       this.order = order;    }    public void CheckInventory()    {       Thread.Sleep(5*1000);       if (order.Equals("ABC Computer"))          availability= true;       else          availability= false;       Console.WriteLine("1st Supplier Inventory "           +for ("+order+"):"+availability);    } } class SecondSupplier {    public string order;    public bool availability;    public SecondSupplier(String order)    {       this.order = order;    }    public void CheckInventory()    {       Thread.Sleep(10*1000);       if (order.Equals("DEF Computer"))          availability = true;       else          availability = false;       Console.WriteLine("2nd Supplier Inventory "          +for ("+order+"):"+availability);    } } 

Running the preceding example should yield the following results. Notice that even though you had started the second supplier's thread earlier than the first one, because of a longer delay in the second supplier, the first supplier's information has been echoed earlier.

 
 1st Supplier Inventory for (ABC Computer):True 2nd Supplier Inventory for (ABC Computer):False 1st Supplier has +ve Inventory 2nd Supplier has -ve Inventory 

To understand the concept of how multiple threads can have synchronized access to shared data, look at the next example, which implements the classical producer and consumer thread example. The Lock keyword provides synchronized access to the data and prevents other threads from accessing the data. Listing 4.14 uses the Monitor class to send a notification to the other waiting thread that the lock has been released (Monitor.Pulse()) so that the other thread that is waiting (using Monitor.Wait()) can continue execution.

Listing 4.14 Synchronizing Multiple Threads
 using System; using System.Threading; public class SyncExample {    public static void Main()    {       Data dt = new Data();       Producer p = new Producer(dt);       Consumer c = new Consumer(dt);       Thread pt = new Thread(new ThreadStart(p.run));       Thread ct = new Thread(new ThreadStart(c.run));       pt.Start();       ct.Start();    } } public class Producer {    private Data data;    public Producer(Data data)    {       this.data = data;    }    public void run()    {       while (true)       {          data.produce();          Thread.Sleep(1000);       }    } } public class Consumer {    private Data data;    public Consumer(Data data)    {       this.data = data;    }    public void run()    {       while (true)       {          data.consume();          Thread.Sleep(1000);       }    } } public class Data {    public int value=0;    public bool isReady = false;    public void produce()    {       lock(this)       {          if (isReady)             Monitor.Wait(this);          value++;          Console.WriteLine("Produced:"+value);          isReady = true;          Monitor.Pulse(this);       }    }    public void consume()    {       lock(this)       {          if (!isReady)             Monitor.Wait(this);          Console.WriteLine("Consumed:"+value);          isReady = false;          Monitor.Pulse(this);       }    } } 

Running the SyncExample should yield the following output:

 
 Produced:1 Consumed:1 Produced:2 Consumed:2 Produced:3 Consumed:3 ... 

In the next section, you will see a more practical use of threads in creating a multithreaded networked server.



Microsoft.Net Kick Start
Microsoft .NET Kick Start
ISBN: 0672325748
EAN: 2147483647
Year: 2003
Pages: 195
Authors: Hitesh Seth

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net