多线程学习 C#

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

一:线程的基本知识

1.Suspend:用于挂起线程

  Resume:用于唤醒线程,由于线程的执行情况不可预知,所以使用挂起和唤醒容易发生死锁的情况

2.join():阻塞调用线程,直到该线程终止

3.Abort:抛出ThreadAbortException异常让线程终止,终止后线程不可唤醒

Interrupt:抛出ThreadInterriptException:异常线程终止,通过捕获异常可以继续执行

二 线程的使用

 class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(TestMethod));//无参的多线程初始化
            Thread t2 = new Thread(new ParameterizedThreadStart(TestMethod));//带参的多线程初始化
            t1.IsBackground = true;
            t2.IsBackground = true;
            t1.Start();           
            t2.Start("hello");
            Console.ReadKey();
        }

        private static void TestMethod()
        {

            Thread.Sleep(10000);
            Console.WriteLine("不带参数的线程函数");
        }
        private static void TestMethod(object obj)
        {
            string datastr = obj as string;
            Console.WriteLine("带参数的线程函数,参数为:{0}", datastr);
        }
    }

三 线程池

线程池维护一个请求队列,线程池的代码从队列提取任务,然后委派给线程池的一个线程执行,线程执行完之后不会被立即销毁,这样既可以在后台执行,又可以减少线程的创建销毁带来的资源开销

class Program
    {
        static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(TestMethod, "Hello");
            Console.ReadKey();
        }

        
        private static void TestMethod(object obj)
        {
            string datastr = obj as string;
            Console.WriteLine("带参数的线程函数,参数为:{0}", datastr);
        }
    }

四 Task 类

使用ThreadPool的QueueUserItem()方法发起一次异步线程执行,但是该方法的最大的问题

是没有一个內建的机制让你知道操作什么时候完成,有没有內建机制在操作完成后获得一个返回值;

为此可以使用System.Threading.Tasks中的Task类

 class Program
    {
        static void Main(string[] args)
        {
            Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000);
            t.Start();
            t.Wait();//等待task完成执行过程
            Console.WriteLine(t.Result);
            Console.ReadKey();
        }

        private static int Sum(int n)
        {
            Int32 sum = 0;
            for (; n > 0; --n)
            {
                checked { sum += n; }
            }
            return sum;
        }
    }

该方法的输出值为从1到1000的加总:500500

一个任务完成之后,它可以启动另一个任务

class Program
    {
        static void Main(string[] args)
        {
            Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 10000);
            t.Start();
           // t.Wait();//等待task完成执行过程
            //Console.WriteLine(t.Result);
            Task cwt = t.ContinueWith(task => Console.WriteLine("The result is {0}", t.Result));
            Console.ReadKey();
        }

        private static int Sum(int n)
        {
            
            Int32 sum = 0;
            for (; n > 0; --n)
            {
                Thread.Sleep(1);
                checked { sum += n; }
            }
            return sum;
        }
    }

重写后的方法会输出The result is:500500

五 委托异步执行

委托的异步调用:BeginInvoke()和EndInvoke()

 public delegate string MyDelegate(object data);
    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate myDelegate = new MyDelegate(TestMethod);
            IAsyncResult result = myDelegate.BeginInvoke("Thread Param", TestCallBack, "Callback Param");

            //异步完成
            string resultstr = myDelegate.EndInvoke(result);

            Console.ReadLine();
        }
        //异步回调函数
        private static void TestCallBack(IAsyncResult data)
        {
            Console.WriteLine(data.AsyncState);
        }
        //线程函数
        private static string TestMethod(object data)
        {
            string datastr = data as string;
            return datastr;
        }
    }

六:

1.Interlocked(原子操作):所有方法都是执行一次原子读或一次写入操作

2.lock()语句避免锁定public类型,否则实例将超出代码的控制范围,定义private对象来锁定

3.Monitor实现线程同步

通过Monitor.Enter()和Monitor.Exit()实现排他锁的获取和释放,获取之后独占资源,不允许其他线程访问

TryEnter方法也可以实现,请求不到资源时不会阻塞等待,可以设置超时时间,获取不到直接返回false

4.ReadWriterLock

当对操作读多写少的时候,为了提高资源利用率,让读操作锁为共享锁,多个线程可以共享读操作,而

写操作独占锁,只允许一个线程操作

5.事件(Event)类实现同步

事件类有两种状态,终止状态和非终止状态终止状态时调用WaitOne,可以请求成功,

通过Set将时间状态设置为终止状态

(1)AutoResetEvent(自动重置事件)

(2)ManualResetEvent(手动重置事件)

6.信号量(Semaphore)

信号量是由内核对象维护的int变量,为0时阻塞线程,大于0时解除阻塞,当一个信号量上的

等待线程解除阻塞后,信号量计数+1.

线程通过WaitOne将信号量减1,通过Release将信号量加1,使用很简单

7.互斥体(Mutex)

独占资源,用法与Semaphore相似

8.跨线程间的同步

通过设置同步对象的名称就可以实现系统级的同步,不同应用程序通过同步对象的名称识别

不同的同步对象

:

猜你喜欢

转载自blog.csdn.net/cdc8596/article/details/87949720