C#中 Thread类的使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangzhiyu1980/article/details/43764615

基本的 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





展开阅读全文

没有更多推荐了,返回首页