c#之线程(一)

2021-04-25 15:30

阅读:414

标签:调用   失败   其他   oid   join()   mon   mount   param   count   

1.线程的状态

(1)创建状态

(2)可运行状态

(3)运行状态

(4)阻塞状态

(5)死亡状态

2.线程同步

(1)lock语句

 lock语句可以将一段代码定义为互斥段,互斥段在同一时刻内只能有一个线程进入。

 

示例:有一笔存款,三个人同时在取钱,每个人可取5次。每次取款时,如果数额超过现有的存款,那么取款被拒绝。一个人在取款的时候另一个人不能取,并且存款的额度不能是0.

    class Program
    {
        static void Main(string[] args)
        {
            //创建3个线程
            Thread[] threads = new Thread[3];
            Account account = new Account(1000);
            for(int i=0;i3;i++)
            {
                threads[i] = new Thread(account.DoTransactions);
                threads[i].Name = "Thread " + (i+1);
                threads[i].Start();
            }  
//下面的形式也行

              Array.ForEach(array, t =>
               {
                 t = new Thread(new ThreadStart(Run));
                 t.Start();
                 t.Join();
               }); 

        }
    }
    class Account
    {
        private int balance { get; set; }
        public Account(int initail)
        {
            balance = initail;
        }
        Random random = new Random();
        /// 
        ///交易
        /// 
        public void DoTransactions()
        {
            //在1到1000之间取随机数。
            WithDraw(random.Next(1,1000));
        }
        /// 
        /// 处理
        /// 
        /// 
        public void WithDraw(int amount)
        {
            if(balance0)
            {
                Console.WriteLine(Thread.CurrentThread.Name+"负存款额");
            }

            lock(this)
            {
                if(balance>=amount)
                {
                    Console.WriteLine($"{Thread.CurrentThread.Name}要取出的数额是{amount},现在的存款是{balance}");
                    balance -= amount;
                    Console.WriteLine($"{Thread.CurrentThread.Name}要取出的数额是{amount},取出后现在的存款是{balance}");
                     
                }
                else
                {
                    Console.WriteLine($"{Thread.CurrentThread.Name}要取出的数额是{amount},被拒绝");
                     
                } 
            }
            Console.ReadKey();
        }

    }

 

 

结果:

Thread 2要取出的数额是227,现在的存款是1000
Thread 2要取出的数额是227,取出后现在的存款是773
Thread 1要取出的数额是295,现在的存款是773
Thread 1要取出的数额是295,取出后现在的存款是478
Thread 3要取出的数额是310,现在的存款是478
Thread 3要取出的数额是310,取出后现在的存款是168

(2)Monitor类

  该类通过向单个线程授予对象锁来控制对对象的访问。当一个线程拥有对象锁的时候,其他任何线程都不能获取该锁。

常用的方法:

Enter(),TryEnter():获取对象锁。

Wait():释放对象上的锁以便允许其他线程锁定和访问对象。在其他线程访问对象时,调用线程将等待。

Pulse(),PulseAll():向一个或多个等待线程发送信号。该信号通知等待线程锁定对象的状态已更改并且锁的所有者准备释放该锁。等待线程被放在对象的就绪队列中,以便可以最后接收对象锁,也就是说处于可运行状态。

Exit():释放对象上的锁。

示例:对给定数量的车皮进行调度。有2个调度员,每次调度10个车皮,保证同一时间只有一个调度员在调度。下面的例子保证了2个调度员没人轮一次,一次调度。

  class Program
    {
        private int ctr = 150;
        static void Main(string[] args)
        {
            // 
            Program account = new Program();
            Thread thread = new Thread(new ThreadStart(account.Decrease));
            //设置成后台线程。只有IsBackground=TRUE的线程才会随着主线程的退出而退出。
            thread.IsBackground = true;
            thread.Name = "thread";
            Thread thread2 = new Thread(new ThreadStart(account.Decrease));
            //设置成后台线程。只有IsBackground=TRUE的线程才会随着主线程的退出而退出。
            thread2.IsBackground = true;
            thread2.Name = "thread2";
            thread.Start();
            thread2.Start();
            thread.Join();
            thread2.Join();
            //所有线程结束
            Console.Write("所有线程结束");
            Console.ReadKey();
        }
        public void Decrease()
        {
            Console.WriteLine($"{Thread.CurrentThread.Name} is  running");
            while (true)
            {
                //获取对象锁
                Monitor.Enter(this);
                if (ctr>=10)
                {
                    ctr -=10;
                    //模拟做一些其他处理
                    Thread.Sleep(1000);
                    Console.WriteLine($"{Thread.CurrentThread.Name}调度车皮,还剩{ctr}");
                    //当前线程调度完车皮后立即让其他线程获取对象锁来调用车皮。
                    Monitor.Exit(this);
                }
                else
                {
                    Console.WriteLine($"{Thread.CurrentThread.Name}调度失败,数量不够");
                    Monitor.Exit(this);
                    break;
                }
            }

        }

    }

 

结果:

thread2 is  running
thread is  running
thread2调度车皮,还剩140
thread调度车皮,还剩130
thread2调度车皮,还剩120
thread调度车皮,还剩110
thread2调度车皮,还剩100
thread调度车皮,还剩90
thread2调度车皮,还剩80
thread调度车皮,还剩70
thread2调度车皮,还剩60
thread调度车皮,还剩50
thread2调度车皮,还剩40
thread调度车皮,还剩30
thread2调度车皮,还剩20
thread调度车皮,还剩10
thread2调度车皮,还剩0
thread调度失败,数量不够
thread2调度失败,数量不够
所有线程结束

 

其中的Join方法,当线程A调用Join方法的时候,其他线程不会执行(包括主线程),等到线程A执行完毕之后再执行其他线程(当然也可以设置阻塞时间)。

 

c#之线程(一)

标签:调用   失败   其他   oid   join()   mon   mount   param   count   

原文地址:https://www.cnblogs.com/anjingdian/p/13258062.html


评论


亲,登录后才可以留言!