• 多线程(二)


    简易阻止:Sleep,阻止给定的时间周期;Join,等待另一个线程完成。

    一旦被阻止,线程立刻放弃分配给他的CPU资源,并且ThreadState属性值改为WaitSleepJoin。

    停止阻止的方式:(1)操作超时(2)通过Thread的Interrupt中断了(3)通过Thread的Abort放弃了.

    Thread.Sleep(Timeout.Infinite);//休眠直到中断

                Thread.Sleep(TimeSpan.FromSeconds(1));//休眠一秒

                Thread.Sleep(0);//暂时的放弃CPU,时间刚刚够其他时间片里的线程执行。

    Join方法也接收一个使用毫秒或用TimeSpan类的超时参数,当Join超时时返回false,如果线程已终止,则返回true。(在阻止是Join保持信息汲取,sleep停止信息汲取)。

     

    锁系统:lock,确保只有一个线程访问某资源,不能跨进程,速度快;

            Mutex, ,确保只有一个线程访问某资源,可以跨进程,速度中等;

            Semaphore,不超过制定数目的线程访问某资源,可以跨进程,速度中等。

     

    任何对所有有关系的线程都可见的对象都可以作为同步对象,但要服从一个硬性规定:它必须是引用类型。也强烈建议同步对象最好私有在类里面(比如一个私有实例字段)防止无意间从外部锁定相同的对象。服从这些规则,同步对象可以兼对象和保护两种作用。

    List<string> list = new List<string>();

            void Test()

            {

                lock (list)

                {

                    list.Add("");

                    //...

                }

            }

    锁并没有以任何方式阻止对同步对象本身的访问,换言之,x.ToString()不会由于另一个线程调用lock(x) 而被阻止,两者都要调用lock(x) 来完成阻止工作。

     

    Interrupt 和 Abort

    static void Main(string[] args)

            {

                Thread t = new Thread(

                    delegate()

                    {

                        try

                        {

                            Thread.Sleep(Timeout.Infinite);

                        }

                        catch (ThreadInterruptedException)

                        {

                            Console.WriteLine("Interrupt!");

                        }

                        Console.WriteLine("finally");

                    }

                    );

                t.Start();

                t.Interrupt();

                Console.Read();

            }

            //Interrupt!

            //finally

    Interrupt中断一个线程仅仅释放其当前的等待状态,并不结束这个线程,后面该干啥干啥!

     

    被阻止的线程也可以通过Abort方法被强制释放,这与调用Interrupt相似,除了用ThreadAbortException异常代替了ThreadInterruptedException异常,此外,异常将被重新抛出在catch里(在试图以有好方式处理异常的时候),直到Thread.ResetAbort在catch中被调用;在这期间线程的ThreadState为AbortRequested。

    在Interrupt 与 Abort 之间最大不同在于它们调用一个非阻止线程所发生的事情。Interrupt继续工作直到下一次阻止发生,Abort在线程当前所执行的位置(可能甚至不在你的代码中)抛出异常。

     //当两个或更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。Mutex 是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
        //可以使用 WaitHandle.WaitOne 方法请求互斥体的所属权。拥有互斥体的线程可以在对 WaitOne 的重复调用中请求相同的互斥体而不会阻止其执行。但线程必须调用 ReleaseMutex 方法同样多的次数以释放互斥体的所属权。Mutex 类强制线程标识,因此互斥体只能由获得它的线程释放。相反,Semaphore 类不强制线程标识。 
        //互斥体有两种类型:局部互斥体和已命名的系统互斥体。如果使用接受名称的构造函数创建 Mutex 对象,则该对象与具有该名称的操作系统对象关联。已命名的系统互斥体在整个操作系统中都可见,可用于同步进程活动。您可以创建多个 Mutex 对象来表示同一个已命名的系统互斥体,也可以使用 OpenExisting 方法打开现有的已命名系统互斥体。(msdn)
    
        class TreadSafe
        {
            private static Mutex mut = new Mutex();//可以在构造函数中命名
            private const int nums = 3;
            private const int arrs = 1;
    
            static void Main(string[] args)
            {
                for (int i = 0; i < nums; i++)
                {
                    Thread t = new Thread(Go);
                    t.Name = string.Format("Thread{0}", i);
                    t.Start();
                }
                Console.Read();
            }
    
            static void Go()
            {
                for (int i = 0; i < arrs; i++)
                {
                    useResource();
                }
            }
    
            private static void useResource()
            {
                mut.WaitOne();
                Console.WriteLine(string.Format("{0}进入", Thread.CurrentThread.Name));
                Thread.Sleep(100);
                Console.WriteLine(string.Format("{0}离开", Thread.CurrentThread.Name));
                mut.ReleaseMutex();
            }
        }
      /*使用 Semaphore 类可控制对资源池的访问。线程通过调用 WaitOne 方法(从 WaitHandle 类继承)进入信号量,并通过调用 Release 方法释放信号量。
    信号量的计数在每次线程进入信号量时减小,在线程释放信号量时增加。当计数为零时,后面的请求将被阻塞,直到有其他线程释放信号量。当所有的线程都已释放信号量时,计数达到创建信号量时所指定的最大值。
    被阻止的线程并不一定按特定的顺序(如 FIFO 或 LIFO)进入信号量。
    线程可通过重复调用 WaitOne 方法多次进入信号量。为释放这些入口中的部分或全部,线程可多次调用无参数的 Release 方法重载,也可以调用 Release(Int32) 方法重载来指定要释放的入口数。
    Semaphore 类不对 WaitOne 或 Release 调用强制线程标识。程序员负责确保线程释放信号量的次数不能太多。例如,假定信号量的最大计数为 2,并且线程 A 和线程 B 同时进入信号量。如果线程 B 中的编程错误导致它两次调用 Release,则两次调用都成功。这样,信号量的计数已满,当线程 A 最终调用 Release 时便会引发 SemaphoreFullException。
    信号量分为两种类型:局部信号量和已命名的系统信号量。如果您使用接受名称的构造函数创建 Semaphore 对象,则该对象与具有该名称的操作系统信号量关联。已命名的系统信号量在整个操作系统中都可见,可用于同步进程活动。您可以创建多个 Semaphore 对象来表示同一个已命名的系统信号量,也可以使用 OpenExisting 方法打开现有的已命名系统信号量。
    局部信号量仅存在于您的进程内。您的进程中任何引用局部 Semaphore 对象的线程都可以使用它。每个 Semaphore 对象都是一个单独的局部信号量。*/
        class Program
        {
            private static Semaphore _pool;
            private static int _padding;
            static void Main(string[] args)
            {
                _pool = new Semaphore(0, 3);
                for (int i = 1; i <= 5; i++)
                {
                    Thread t = new Thread(new ParameterizedThreadStart(Go));
                    t.Start(i);
                }
                Thread.Sleep(500);
                Console.WriteLine("主线程将信号量增加到3");
                _pool.Release(3);
                Console.Read();
            }
    
            static void Go(object num)
            {
                Console.WriteLine("Thread{0}开始,并等待Semaphore", num);
                _pool.WaitOne();
    
                int padding = Interlocked.Add(ref _padding, 100);//原子操作,两个值相加,把第一个值更新为两值和
                Console.WriteLine("Thread{0}进入Semaphore", num);
    
                Thread.Sleep(1000 + padding);
                Console.WriteLine("Thread{0} 离出 semaphore.", num);
                Console.WriteLine("Thread{0} 前一个信号量数: {1}", num, _pool.Release());
            }
        }
    class Program
        {
            /*AutoResetEvent 允许线程通过发信号互相通信。 通常,当线程需要独占访问资源时使用该类。 
    线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号。 如果 AutoResetEvent 为非终止状态,则线程会被阻止,并等待当前控制资源的线程通过调用 Set 来通知资源可用。 
    调用 Set 向 AutoResetEvent 发信号以释放等待线程。 AutoResetEvent 将保持终止状态,直到一个正在等待的线程被释放,然后自动返回非终止状态。 如果没有任何线程在等待,则状态将无限期地保持为终止状态。 
    如果当 AutoResetEvent 为终止状态时线程调用 WaitOne,则线程不会被阻止。 AutoResetEvent 将立即释放线程并返回到非终止状态。*/
            static AutoResetEvent wh = new AutoResetEvent(false);
            static void Main()
            {
                new Thread(Go).Start();
                Thread.Sleep(2000);
                wh.Set();//释放
                Console.Read();
            }
    
            static void Go()
            {
                Console.WriteLine("waitting..........");
                wh.WaitOne();//暂停
                Console.WriteLine("OK");
            }
        }
     //生产者/消费者队列
        class ProducerCustomerQueue : IDisposable
        {
            AutoResetEvent wh = new AutoResetEvent(false);
            Thread worker;
            object locker = new object();
            Queue<string> tasks = new Queue<string>();
    
            public ProducerCustomerQueue()
            {
                worker = new Thread(work);
                worker.Start();
            }
    
            public void EnqueueTask(string task)
            {
                lock (locker)
                {
                    tasks.Enqueue(task);
                }
                wh.Set();
            }
    
            void work()
            {
                while (true)
                {
                    string task = null;
                    lock (locker)
                    {
                        if (tasks.Count > 0)
                        {
                            task = tasks.Dequeue();
                            if (task == null) //tag
                            {
                                return;
                            }
                        }
                        if (task != null)
                        {
                            Console.WriteLine("执行任务" + task);
                            Thread.Sleep(1000);
                        }
                        else
                        {
                            wh.WaitOne();//没有任务了,等待信号
                        }
                    }
                }
            }
    
            #region IDisposable 成员
    
            public void Dispose()
            {
                EnqueueTask(null);//goto:tag.告诉消费者退出
                worker.Join();//等待消费者线程完成
                wh.Close();//释放所有资源
            }
    
            #endregion
        }
    
        class TreadSafe
        {
            static void Main(string[] args)
            {
                using (ProducerCustomerQueue q = new ProducerCustomerQueue())
                {
                    q.EnqueueTask("hello");
                    for (int i = 0; i < 10; i++)
                    {
                        q.EnqueueTask("say " + i);
                    }
                    q.EnqueueTask("Bye");
                }
                Console.Read();
            }
        }
  • 相关阅读:
    复合索引的列顺序判断
    sqlserver 存储过程中使用临时表到底会不会导致重编译
    Sql Server参数化查询之where in和like实现详解
    浅析SqlServer简单参数化模式下对sql语句自动参数化处理以及执行计划重用
    SQL优化 查询语句中,用 inner join 作为过滤条件和用where作为过滤条件的区别
    通过手动创建统计信息优化sql查询性能案例
    SQL Server 并行操作优化,避免并行操作被抑制而影响SQL的执行效率
    SQL Server 执行计划利用统计信息对数据行的预估原理二(为什么复合索引列顺序会影响到执行计划对数据行的预估)
    C#实现文件数据库
    ASP.NET DropDownList1_SelectedIndexChanged使用
  • 原文地址:https://www.cnblogs.com/hometown/p/3243017.html
Copyright © 2020-2023  润新知