Introduction to multithreading and parallel computing under. NET

Source: Internet
Author: User

In this section, we define a simple thread pool based on the core idea of the thread pool:

1) The number of threads used in the pool is not less than a certain number, not more than a certain number

2) create a pool when there are not enough threads, and reclaim the pool when there are rich threads.

3) task queue. When no threads are available, the task waits.

Our goal is to achieve these "requirements" without considering performance (such as waiting for a while to create new thread policies) and special processing (exceptions ), in the process of implementing this requirement, we also reviewed the basic concepts of thread and thread synchronization.

First, encapsulate the status data required by the task delegate and the task into an object:

Public class WorkItem
{
Public WaitCallback Action {get; set ;}
Public object State {get; set ;}

Public WorkItem (WaitCallback action, object state)
{
This. Action = action;
This. State = state;
}
} Then create an object as a thread in the thread pool:

Public class SimpleThreadPoolThread
{
PRivate object locker = new object ();
Private AutoResetEvent are = new AutoResetEvent (false );
Private WorkItem wi;
Private Thread t;
Private bool B = true;
Private bool isWorking;

Public bool IsWorking
{
Get
{
Lock (locker)
{
Return isWorking;
}
}
}
Public event action <simplethreadpoolthread> workcomplete;

Public simplethreadpoolthread ()
{
Lock (locker)
{
// No actual task currently
Isworking = false;
}
T = new thread (work) {isbackground = true };
T. Start ();
}

Public void SetWork (WorkItem wi)
{
This. wi = wi;
}

Public void StartWork ()
{
// Send a signal
Are. Set ();
}

Public void StopWork ()
{
// Empty task
Wi = null;
// Stop the thread Loop
B = false;
// End the thread by sending a signal
Are. Set ();
}

Private void Work ()
{
While (B)
{
// No task, waiting for Signal
Are. WaitOne ();
If (wi! = Null)
{
Lock (locker)
{
// Start
IsWorking = true;
}
// Execute the task
Wi. Action (wi. State );
Lock (locker)
{
// End
IsWorking = false;
}
// End the event
WorkComplete (this );
}
}
} For details about the code, see the comments to describe the overall structure of the Code:

1) because this thread is reused by tasks in the thread pool, the tasks in the thread are in a loop. Unless the thread pool is intended to recycle this thread, the End Task of the Loop will not be exited.

2) use automatic semaphores to wait when the thread does not have a task. The thread pool sends a signal after the task is set externally to execute the actual task. After the task is executed, it continues to wait.

3) The thread exposes a completed event. The thread pool can hook up the handling method and update the thread pool status after the task is completed.

4) All threads in the thread pool are background threads.

Next we will implement the thread pool:

Public class simplethreadpool: idisposable
{
Private object locker = new object ();
Private bool B = true;
Private int minthreads;
Private int maxthreads;
Private int currentactivethreadcount;
Private list <simplethreadpoolthread> simplethreadpoolthreadlist = new list <simplethreadpoolthread> ();
Private queue <workitem> workitemqueue = new queue <workitem> ();

Public int currentactivethreadcount
{
Get
{
Lock (locker)
{
Return currentactivethreadcount;
}
}

}

Public int currentthreadcount
{
Get
{
Lock (locker)
{
Return simplethreadpoolthreadlist. count;
}
}
}

Public int currentqueuedworkcount
{
Get
{
Lock (locker)
{
Return workItemQueue. Count;
}
}
}

Public SimpleThreadPool ()
{
MinThreads = 4;
MaxThreads = 25;
Init ();
}

Public SimpleThreadPool (int minThreads, int maxThreads)
{
If (minThreads> maxThreads)
Throw new ArgumentException ("minThreads> maxThreads", "minThreads, maxThreads ");
This. minThreads = minThreads;
This. maxThreads = maxThreads;
Init ();
}

Public void QueueUserWorkItem (WorkItem wi)
{
Lock (locker)
{
// Task Column
WorkItemQueue. Enqueue (wi );
}
}

Private void Init ()
{
Lock (locker)
{
// Create the minimum thread at the beginning
For (int I = 0; I <minThreads; I ++)
{
CreateThread ();
}
CurrentActiveThreadCount = 0;
}
New Thread (Work) {IsBackground = true}. Start ();
}

Private SimpleThreadPoolThread CreateThread ()
{
SimpleThreadPoolThread t = new SimpleThreadPoolThread ();
// Hook task end event
T. WorkComplete + = new Action <SimpleThreadPoolThread> (t_WorkComplete );
// Thread Columns
SimpleThreadPoolThreadList. Add (t );
Return t;
}

Private void Work ()
{
// Main loop of the thread pool
While (B)
{
Thread. Sleep (100 );
Lock (locker)
{
// If there is a task in the queue and the current thread is smaller than the maximum thread
If (workItemQueue. Count> 0 & CurrentActiveThreadCount <maxThreads)
{
WorkItem wi = workItemQueue. Dequeue ();
// Find Idle threads
Simplethreadpoolthread availablethread = simplethreadpoolthreadlist. firstordefault (t => T. isworking = false );
// Create if none exist
If (availablethread = NULL)
Availablethread = createthread ();
// Set the task
AvailableThread. SetWork (wi );
// Start the task
AvailableThread. StartWork ();
// Add an active thread
CurrentActiveThreadCount ++;
}
}
}
}

Private void t_WorkComplete (SimpleThreadPoolThread t)
{
Lock (locker)
{
// Reduce active threads
CurrentActiveThreadCount --;
// If the current number of threads is richer and more than the minimum number of threads
If (workItemQueue. Count + currentActiveThreadCount) <minThreads & CurrentThreadCount> minThreads)
{
// Stop finished threads
T. StopWork ();
// Delete a thread from the thread pool
SimpleThreadPoolThreadList. Remove (t );
}
}
}

Public void Dispose ()
{
// Stop all threads
Foreach (var t in simpleThreadPoolThreadList)
{
T. StopWork ();
}
// The main cycle of the thread pool stops.
B = false;
}
} The thread pool structure is as follows:

1) You can set the minimum and maximum threads of the thread pool in the constructor.

2) Maintain a list of tasks and threads in a thread pool.

3) The minimum number of threads defined during thread pool Initialization

4) The main loop of the thread pool is processed every 20 milliseconds. If there is a task and the thread pool can still process the task, first find the idle thread and create

5) set the task delegate and issue the semaphore to start the task.

6) The Thread Pool provides three attributes to view the number of active threads, the total number of threads, and the number of tasks in the current queue.

7) in the callback event of task completion, we determine that if the current thread is richer and has more than the minimum thread, the thread will be recycled.

8) the thread pool is an IDispose object. Stop all threads in the Dispose () method and then stop the main loop of the thread pool.

Write a piece of code to test the thread pool:

Using (simplethreadpool T = new simplethreadpool (2, 4 ))
{
Stopwatch sw2 = stopwatch. startnew ();
For (INT I = 0; I <10; I ++)
{
T. queueuserworkitem (New workitem (Index =>
{
Console. writeline (string. format ("# {0 }:{ 1}/{2}", thread. currentthread. managedthreadid, datetime. now. tostring ("mm: SS"), index ));
Console. writeline (string. format ("currentactivethread: {0}/currentthread: {1}/currentqueuedwork: {2}", T. currentactivethreadcount, T. currentthreadcount, T. currentqueuedworkcount ));
Thread. Sleep (1000 );
}), I ));
}
While (t. CurrentQueuedWorkCount> 0 | t. CurrentActiveThreadCount> 0)
{
Thread. Sleep (10 );
}
Console. WriteLine ("All work completed ");
Console. writeLine (string. format ("CurrentActiveThread: {0}/CurrentThread: {1}/CurrentQueuedWork: {2}", t. currentActiveThreadCount, t. currentThreadCount, t. currentQueuedWorkCount ));
Console. WriteLine (sw2.ElapsedMilliseconds );
} In the code, we push 10 tasks to the thread pool. Each task takes one second to execute. Before the task is executed, the Id of the thread to which the current task belongs, the current time and status value are output. Then, several state attributes of the thread pool are output. The main thread cyclically waits for all tasks to finish and then outputs the thread pool status attributes again and the time required to complete all tasks:

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.