代码改变世界

.Net中多线程类的使用和总结

2017-06-04 17:03  Dirichlet  阅读(928)  评论(0编辑  收藏  举报

lock, Monitor, Thread, Join, BackGroundWorker.   消费者和生产者。Async 委托Invoke

TypeHandle中BlockIndex。

http://msdn.microsoft.com/zh-cn/library/ms173179(v=vs.80).aspx

 

a. lock相当于 Monitor.Enter, Monitor.Exit. 必须lock引用类型对象。

不能lock公共对象,否则实例将超出代码的控制范围,容易引发死锁。 常见的结构 lock (this)lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:

对于一段代码锁住a,等待b,另一段代码锁住b,等待a,就会产生死锁

       lock(thisLock)
        {
            if (balance >= amount)
            {
                Console.WriteLine("Balance before Withdrawal :  " + balance);
                Console.WriteLine("Amount to Withdraw        : -" + amount);
                balance = balance - amount;
                Console.WriteLine("Balance after Withdrawal  :  " + balance);
                return amount;
            }
            else
            {
                return 0; // transaction rejected
            }
        }

lock相当于如下:
if(Monitor.TryEnter(m_inputQueue))
{
    try
    {
         m_inputQueue.Enqueue(qValue);
    }
    finally
    {
     Monitor.Exit(m_inputQueue);
    }
}
Monitor.Enter(x);
try {
    // Code that needs to be protected by the monitor.
}
finally {
    // Always use Finally to ensure that you exit the Monitor.
    // The following line creates another object containing 
    // the value of x, and throws SynchronizationLockException
    // because the two objects do not match.
    Monitor.Exit(x);
}

 


b. volatile关键字

注意下面的private volatile bool _shouldStop; 加volatitle修饰后可以保证多个线程可以安全的访问此bool变量,这里的用bool表示状态是不需要同步的,并不是volatile保证了其原子性,
而仅仅是因为他是个简单的bool型变量。votitle本身并不能保证绝对的原子性,如果volatile修饰的是复杂一些结构体,类对象,如果不使用线程同步,会产生非预期的中间状态数据。
using System;
using System.Threading;

public class Worker
{
    // This method will be called when the thread is started.
    public void DoWork()
    {
        while (!_shouldStop)
        {
            Console.WriteLine("worker thread: working...");
        }
        Console.WriteLine("worker thread: terminating gracefully.");
    }
    public void RequestStop()
    {
        _shouldStop = true;
    }
    // Volatile is used as hint to the compiler that this data
    // member will be accessed by multiple threads.
    private volatile bool _shouldStop;
}

public class WorkerThreadExample
{
    static void Main()
    {
        // Create the thread object. This does not start the thread.
        Worker workerObject = new Worker();
        Thread workerThread = new Thread(workerObject.DoWork);

        // Start the worker thread.
        workerThread.Start();
        Console.WriteLine("main thread: Starting worker thread...");

        // Loop until worker thread activates.
        while (!workerThread.IsAlive);

        // Put the main thread to sleep for 1 millisecond to
        // allow the worker thread to do some work:
        Thread.Sleep(1);

        // Request that the worker thread stop itself:
        workerObject.RequestStop();

        // Use the Join method to block the current thread 
        // until the object's thread terminates.
        workerThread.Join();
        Console.WriteLine("main thread: Worker thread has terminated.");
    }
}

b. ManualResetEvent
doneEvents[i] = new ManualResetEvent(false);

// 1. Set event. Raise singal
doneEvents[i].Set();

// 2. Wait the signal until all the events raise the singal.
WaitHandle.WaitAll(doneEvents);
AutoResetEvent,


c. ThreadPool线程池
后台执行任务的线程集合,多用于服务器等需要多个线程的场合。为每个请求分配一个线程来执行请求,执行完请求后线程返回到队列等待再次被使用,
避免了每个任务创建/销毁新线程的开销。如果请求过来之后没有可用的线程需要进队列排队。
http://msdn.microsoft.com/zh-cn/library/3dasc8as(v=vs.90).aspx
using System;
using System.Threading;

public class Fibonacci
{
    public Fibonacci(int n, ManualResetEvent doneEvent)
    {
        _n = n;
        _doneEvent = doneEvent;
    }

    // Wrapper method for use with thread pool.
    public void ThreadPoolCallback(Object threadContext)
    {
        int threadIndex = (int)threadContext;
        Console.WriteLine("thread {0} started...", threadIndex);
        _fibOfN = Calculate(_n);
        Console.WriteLine("thread {0} result calculated...", threadIndex);
        _doneEvent.Set();
    }

    // Recursive method that calculates the Nth Fibonacci number.
    public int Calculate(int n)
    {
        if (n <= 1)
        {
            return n;
        }

        return Calculate(n - 1) + Calculate(n - 2);
    }

    public int N { get { return _n; } }
    private int _n;

    public int FibOfN { get { return _fibOfN; } }
    private int _fibOfN;

    private ManualResetEvent _doneEvent;
}

public class ThreadPoolExample
{
    static void Main()
    {
        const int FibonacciCalculations = 10;

        // One event is used for each Fibonacci object
        ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
        Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
        Random r = new Random();

        // Configure and launch threads using ThreadPool:
        Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
        for (int i = 0; i < FibonacciCalculations; i++)
        {
            doneEvents[i] = new ManualResetEvent(false);
            Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]);
            fibArray[i] = f;
            ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
        }

        // Wait for all threads in pool to calculation...
        WaitHandle.WaitAll(doneEvents);
        Console.WriteLine("All calculations are complete.");

        // Display the results...
        for (int i= 0; i<FibonacciCalculations; i++)
        {
            Fibonacci f = fibArray[i];
            Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
        }
    }
}

e. AutoResetEvent