C#中 Thread类的使用

来源:互联网 发布:淘宝网购物车登录界面 编辑:程序博客网 时间:2024/05/16 17:09

基本的 Thread 框架

基本的 Thread 程序结构,由工作函数,start 和 join 组成

Thread类是比较常用的一个类,这里总结了一些基本的使用方法和程序示例,以备以后查用。


https://msdn.microsoft.com/zh-cn/library/system.threading.thread.aspx


using System;using System.Threading;// Simple threading scenario:  Start a static method running// on a second thread.public class ThreadExample{    // The ThreadProc method is called when the thread starts.    // It loops ten times, writing to the console and yielding     // the rest of its time slice each time, and then ends.    public static void ThreadProcA()    {        for (int i = 0; i < 10; i++)        {            Console.WriteLine("ThreadProc A: {0}", i);            Thread.Sleep(0);        }    }    public static void ThreadProcB()    {        for (int i = 0; i < 10; i++)        {            Console.WriteLine("ThreadProc B: {0}", i);            // Yield the rest of the time slice.            Thread.Sleep(0);        }    }    public static void Main()    {        Console.WriteLine("Main thread: Start a second thread.");        // The constructor for the Thread class requires a ThreadStart         // delegate that represents the method to be executed on the         // thread.  C# simplifies the creation of this delegate.        Thread t = new Thread(new ThreadStart(ThreadProcA));        Thread t1 = new Thread(new ThreadStart(ThreadProcB));        // Start ThreadProc.  Note that on a uniprocessor, the new         // thread does not get any processor time until the main thread         // is preempted or yields.  Uncomment the Thread.Sleep that         // follows t.Start() to see the difference.        t.Start();        t1.Start();        //Thread.Sleep(0);        for (int i = 0; i < 4; i++)        {            Console.WriteLine("Main thread: Do some work.");            Thread.Sleep(0);        }        Console.WriteLine("Main thread: Call Join(), to wait until ThreadProc ends.");        t.Join();        t1.Join();        Console.WriteLine("Main thread: ThreadProc.Join has returned.  Press Enter to end program.\n");        Console.ReadLine();    }}

这仅仅是一个创建两个线程的例子,但并不太符合实际应用的情况

此时的输出结果A 与 B 随机打印。


pic_1




使用 Mutex

使用多线程,无法避免的一定是线程间的同步互斥,及对于共享资源的访问,这里的Mutex便是线程互斥的一种方式。

当两个或更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。使用Mutex 时,它只向一个线程开放访问权。 如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体

https://msdn.microsoft.com/zh-cn/library/System.Threading.Mutex(v=vs.80).aspx


using System;using System.Threading;// Simple threading scenario:  Start a static method running// on a second thread.public class ThreadExample{    private static Mutex m_Mutex = new Mutex();    // The ThreadProc method is called when the thread starts.    // It loops ten times, writing to the console and yielding     // the rest of its time slice each time, and then ends.    public static void ThreadProcA()    {        m_Mutex.WaitOne();        for (int i = 0; i < 10; i++)        {            Console.WriteLine("ThreadProc A: {0}", i);            Thread.Sleep(0);        }        m_Mutex.ReleaseMutex();    }    public static void ThreadProcB()    {        m_Mutex.WaitOne();        for (int i = 0; i < 10; i++)        {            Console.WriteLine("ThreadProc B: {0}", i);            // Yield the rest of the time slice.            Thread.Sleep(0);        }        m_Mutex.ReleaseMutex();    }    public static void Main()    {        Console.WriteLine("Main thread: Start a second thread.");        // The constructor for the Thread class requires a ThreadStart         // delegate that represents the method to be executed on the         // thread.  C# simplifies the creation of this delegate.        Thread t = new Thread(new ThreadStart(ThreadProcA));        Thread t1 = new Thread(new ThreadStart(ThreadProcB));        // Start ThreadProc.  Note that on a uniprocessor, the new         // thread does not get any processor time until the main thread         // is preempted or yields.  Uncomment the Thread.Sleep that         // follows t.Start() to see the difference.        t.Start();        t1.Start();        //Thread.Sleep(0);        m_Mutex.WaitOne();        for (int i = 0; i < 4; i++)        {            Console.WriteLine("Main thread: Do some work.");            Thread.Sleep(0);        }        m_Mutex.ReleaseMutex();        Console.WriteLine("Main thread: Call Join(), to wait until ThreadProc ends.");        t.Join();        t1.Join();        Console.WriteLine("Main thread: ThreadProc.Join has returned.  Press Enter to end program.\n");        Console.ReadLine();    }}


此时的输出结果固定。

pic_2





使用 Monitor

Monitor 是线程间同步互斥的另一种方式,与Mutex最直接的不同是它是与对象关联的。相似点确实很多,都可以对一个临界区进行保护,并且成对出现。



Monitor 类通过向单个线程授予对象锁来控制对对象的访问。 对象锁提供限制访问 代码块(通常称为临界区)的能力。当一个线程拥有对象的锁时,其他任何线程都不能获取该锁。


Monitor 具有以下功能:
    -    它根据需要与某个对象相关联。
    -    它是未绑定的,也就是说可以直接从任何上下文调用它。
    -    不能创建 Monitor 类的实例。


同时需要注意的是,Monitor.Enter()函数传入的是一个对象,如果传入了一个简单类型,它会引发装箱操作,这时它所加锁的是一个新的对象。

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


主要关注其中 3个线程函数: ThreadProcAdd, ThreadProcRemove, ThreadProcShow。

主要的意图是在程序运行中3个线程操作同一个队列,进行多次的读,写和删除,每一次操作一组5个数据,这一组数据为不可分割的,。



using System;using System.Collections;using System.Threading;namespace MonitorCS2{    /// <summary>    /// Summary description for Class1.    /// </summary>    class MonitorSample    {        //Define the queue to safe thread access.        private static Queue m_inputQueue = new Queue();        public MonitorSample()        {        }        //Add an element to the queue and obtain the monitor lock for the queue object.        public void AddElement(object qValue)        {            //Lock the queue.            Monitor.Enter(m_inputQueue);            //Add element            m_inputQueue.Enqueue(qValue);            //Unlock the queue.            Monitor.Exit(m_inputQueue);        }        //Try to add an element to the queue.        //Add the element to the queue only if the queue object is unlocked.        public bool AddElementWithoutWait(object qValue)        {            //Determine whether the queue is locked             if (!Monitor.TryEnter(m_inputQueue))                return false;            m_inputQueue.Enqueue(qValue);            Monitor.Exit(m_inputQueue);            return true;        }        //Try to add an element to the queue.         //Add the element to the queue only if during the specified time the queue object will be unlocked.        public bool WaitToAddElement(object qValue, int waitTime)        {            //Wait while the queue is locked.            if (!Monitor.TryEnter(m_inputQueue, waitTime))                return false;            m_inputQueue.Enqueue(qValue);            Monitor.Exit(m_inputQueue);            return true;        }        //Delete all elements that equal the given object and obtain the monitor lock for the queue object.        public void DeleteElement(object qValue)        {            //Lock the queue.            Monitor.Enter(m_inputQueue);            int counter = m_inputQueue.Count;            while (counter > 0)            {                //Check each element.                object elm = m_inputQueue.Dequeue();                if (!elm.Equals(qValue))                {                    m_inputQueue.Enqueue(elm);                }                --counter;            }            //Unlock the queue.            Monitor.Exit(m_inputQueue);        }        //Print all queue elements.        public void PrintAllElements()        {            //Lock the queue.            Monitor.Enter(m_inputQueue);            IEnumerator elmEnum = m_inputQueue.GetEnumerator();            while (elmEnum.MoveNext())            {                //Print the next element.                Console.WriteLine(elmEnum.Current.ToString());            }            //Unlock the queue.            Monitor.Exit(m_inputQueue);        }        public static void ThreadProcAdd()        {            for (int j = 0; j < 5; j++)            {                try                {                    //Lock the queue.                    Monitor.Enter(m_inputQueue);                    for (int i = 0; i < 5; i++)                    {                        //Add element                        m_inputQueue.Enqueue(i);                        Thread.Sleep(50);                        Console.WriteLine("ThreadProc Add: {0} per 50 ms", i);                    }                }                catch (Exception ex)                {                    Console.WriteLine(ex.ToString());                }                finally                {                    //Unlock the queue.                    Monitor.Exit(m_inputQueue);                                }                Thread.Sleep(200);            }        }        public static void ThreadProcShow()        {            for (int i = 0; i < 20; i++)            {                try                {                    //Lock the queue.                    Monitor.Enter(m_inputQueue);                    IEnumerator elmEnum = m_inputQueue.GetEnumerator();                    Console.WriteLine("Show: ");                    while (elmEnum.MoveNext())                    {                        //Print the next element.                        Console.Write(elmEnum.Current.ToString() + ", ");                    }                    Console.WriteLine();                }                catch (Exception ex)                {                    Console.WriteLine(ex.ToString());                }                finally                {                    //Unlock the queue.                    Monitor.Exit(m_inputQueue);                }                Thread.Sleep(100);            }        }        public static void ThreadProcRemove()        {            for (int j = 0; j < 5; j++)            {                try                {                    //Lock the queue.                    Monitor.Enter(m_inputQueue);                    int counter = m_inputQueue.Count;                    while (counter > 0)                    {                        //Check each element.                        object elm = m_inputQueue.Dequeue();                        Console.WriteLine("ThreadProc remove: {0} per 50 ms", (int)elm);                        Thread.Sleep(50);                        --counter;                    }                }                catch (Exception ex)                {                    Console.WriteLine(ex.ToString());                }                finally                {                    //Unlock the queue.                    Monitor.Exit(m_inputQueue);                }                Thread.Sleep(200);            }        }        static void Main(string[] args)        {            Thread ta = new Thread(new ThreadStart(ThreadProcAdd));            Thread tr = new Thread(new ThreadStart(ThreadProcRemove));            Thread ts = new Thread(new ThreadStart(ThreadProcShow));            ta.Start();            tr.Start();            ts.Start();            ta.Join();            tr.Join();            ts.Join();            Console.WriteLine("Main thread: ThreadProc.Join has returned.  Press Enter to end program.\n");            Console.ReadLine();        }    }}


测试结果:

从测试结果可以看出,插入操作和删除操作都是整体出现的,并没有被打断的迹象。

pic_3





0 0