• 多线程备忘


    1.以前一直在用多线程,但对于多个线程完成一个任务时,如何汇合到主线程不太清楚,有时竟傻到去记录每个线程的状态来轮询等待(此处不讨论线程池),下面我写了一个例子,虽然和自己预想的结果有点出入,但确定实现了这个功能,就是Thread.Join方法,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    
    namespace MultiThreadTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                var thread1 = new Thread(new ThreadStart(ThreadProc1));
                var thread2 = new Thread(new ThreadStart(ThreadProc2));
                thread1.Start();
                thread2.Start();
                
                thread1.Join();
                thread2.Join();
    
                Console.WriteLine("{0} All threads end.", DateTime.Now);
                Console.ReadLine();
            }
    
            public static void ThreadProc1()
            {
                Console.WriteLine("{0} Thread 1 start.", DateTime.Now);
                Thread.Sleep(5000);
                Console.WriteLine("{0} Thread 1 end.", DateTime.Now);
            }
    
            public static void ThreadProc2()
            {
                Console.WriteLine("{0} Thread 2 start.", DateTime.Now);
                Thread.Sleep(3000);
                Console.WriteLine("{0} Thread 2 end.", DateTime.Now);
            }
        }
    }

    输出结果如下:

    2012-11-30 13:54:41 Thread 1 start.
    2012-11-30 13:54:41 Thread 2 start.
    2012-11-30 13:54:44 Thread 2 end.
    2012-11-30 13:54:46 Thread 1 end.
    2012-11-30 13:54:46 All threads end.  

    2.用Child Task也可以实现这一效果:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace MultiThreadTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                var tasks = new Task(() => 
                {
                    var task1 = new Task(ThreadProc1,TaskCreationOptions.AttachedToParent);
                    var task2 = new Task(ThreadProc2,TaskCreationOptions.AttachedToParent);
                    task1.Start();
                    task2.Start();
                });
                tasks.Start();
                tasks.Wait();
                Console.WriteLine("{0} All threads end.", DateTime.Now);
                Console.ReadLine();
            }
    
            public static void ThreadProc1()
            {
                Console.WriteLine("{0} Thread 1 start.", DateTime.Now);
                Thread.Sleep(5000);
                Console.WriteLine("{0} Thread 1 end.", DateTime.Now);
            }
    
            public static void ThreadProc2()
            {
                Console.WriteLine("{0} Thread 2 start.", DateTime.Now);
                Thread.Sleep(3000);
                Console.WriteLine("{0} Thread 2 end.", DateTime.Now);
            }
        }
    }

    输出结果如下:

    2012-11-30 16:27:49 Thread 2 start.
    2012-11-30 16:27:49 Thread 1 start.
    2012-11-30 16:27:52 Thread 2 end.
    2012-11-30 16:27:54 Thread 1 end.
    2012-11-30 16:27:54 All threads end.

    3.异步线程UI访问时会报错,可以使用委托通过this.invoke来访问:

    如果没有参数传递:

       1)winform中可以这样访问

    this.Invoke(new MethodInvoker(delegate() { 
          //code here              
    }));
    
    pictureBox1.Invoke((Action)delegate()
    {
            pictureBox1.Update();
    });

    如果有参数:

    private delegate void SetResult(string result);
    
    SetResult delSetResult = setResult;
    this.Invoke(delSetResult, result); //this为UI线程对象

    最近发现从c++的com接口回调时,以上方法都无效,直接卡住,应该假死。创建一个新线程代理一下即可解决,

    var t = new Thread(new ParameterizedThreadStart(delegate(object p){
                    var args = p as Form1.ValidateEventReciever.ValidateEventArgs;
                    this.Invoke(new MethodInvoker(delegate()
                    {
                        txtResult.Text = args.EventMessage;
                    }));
                }));
                t.Start(e);

    this 为当前 form 对象 

    2)WPF中可以这样访问

    public delegate void MethodInvoker();
    
    this.Dispatcher.Invoke(new MethodInvoker(delegate()
    {
         btnLogin.IsEnabled = true;
    }));

    4.线程池使用示例。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Diagnostics;
    
    namespace ConsoleApplication7
    {
        class Program
        {
            private static Random rnd = new Random();
    
            static void Main(string[] args)
            {
                var events = new List<ManualResetEvent>();
    
                for (var i = 0; i < 10; i++)
                {
                    var resetEvent = new ManualResetEvent(false);
                    ThreadPool.QueueUserWorkItem(
                        arg =>
                        {
                            doWork(arg);
                            resetEvent.Set();
                        }, i);
                    events.Add(resetEvent);
                }
    
                WaitHandle.WaitAll(events.ToArray());
    
                Debug.Print("{0}\t All task Completed", DateTime.Now);
            }
    
            public static void doWork(object p)
            {
                var id = p.ToString();
                var seconds = rnd.Next(1000, 10000);
                Thread.Sleep(seconds);
                Debug.Print("{0}\tTask [{1}] Completed", DateTime.Now, id);
            }
        }
    }

    输出结果如下:

    06/30/2018 10:42:25 Task [3] Completed
    06/30/2018 10:42:28 Task [2] Completed
    06/30/2018 10:42:29 Task [5] Completed
    06/30/2018 10:42:30 Task [1] Completed
    06/30/2018 10:42:32 Task [6] Completed
    06/30/2018 10:42:32 Task [7] Completed
    06/30/2018 10:42:32 Task [4] Completed
    06/30/2018 10:42:33 Task [0] Completed
    06/30/2018 10:42:34 Task [8] Completed
    06/30/2018 10:42:35 Task [9] Completed
    06/30/2018 10:42:35 All task Completed

     5. 多线程综合运用示例:

    class Program
        {
            static void Main(string[] args)
            {
                demo4();
                Console.ReadLine();
            }
    
            static void demo1()
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object obj) {
                    for (var i = 0; i < 5; i++)
                    {
                        Console.WriteLine("{0}\ti={1}", DateTime.Now, i);
                        Thread.Sleep(10);
                    }
                }));
    
                ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object obj)
                {
                    for (var j = 0; j < 5; j++)
                    {
                        Console.WriteLine("{0}\tj={1}", DateTime.Now, j);
                        Thread.Sleep(15);
                    }
                }));
    
                ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object obj)
                {
                    for (var k = 0; k < 5; k++)
                    {
                        Console.WriteLine("{0}\tk={1}", DateTime.Now, k);
                        Thread.Sleep(13);
                    }
                }));
            }
    
            static void demo2()
            {
                var t1 = new Task(new Action(delegate()
                {
                    for (var i = 0; i < 5; i++)
                    {
                        Console.WriteLine("{0}\ti={1}", DateTime.Now, i);
                        Thread.Sleep(10);
                    }
                }));
    
                t1.Start();
    
                var t2 = new Task(new Action(delegate()
                {
                    for (var j = 0; j < 5; j++)
                    {
                        Console.WriteLine("{0}\tj={1}", DateTime.Now, j);
                        Thread.Sleep(15);
                    }
                }));
    
                t2.Start();
    
                var t3 = new Task(new Action(delegate()
                {
                    for (var k = 0; k < 5; k++)
                    {
                        Console.WriteLine("{0}\tk={1}", DateTime.Now, k);
                        Thread.Sleep(13);
                    }
                }));
    
                t3.Start();
    
                t1.Wait();
                t2.Wait();
                t3.Wait();
    
                Console.WriteLine("所有任务执行完成");
            }
    
            static void demo3()
            {
                //经测试,子任务必须在父任务内部实例化,否则无法实现任务进度联动
                var tasks = new Task(() =>
                {
                    new Task(() =>
                    {
                        for (var i = 0; i < 5; i++)
                        {
                            Console.WriteLine("{0}\ti={1}", DateTime.Now, i);
                            Thread.Sleep(10);
                        }
                    }, TaskCreationOptions.AttachedToParent).Start();
    
                    new Task(() =>
                    {
                        for (var j = 0; j < 5; j++)
                        {
                            Console.WriteLine("{0}\tj={1}", DateTime.Now, j);
                            Thread.Sleep(15);
                        }
                    }, TaskCreationOptions.AttachedToParent).Start();
    
                    new Task(() =>
                    {
                        for (var k = 0; k < 5; k++)
                        {
                            Console.WriteLine("{0}\tk={1}", DateTime.Now, k);
                            Thread.Sleep(13);
                        }
                    }, TaskCreationOptions.AttachedToParent).Start();
    
                });
    
                tasks.Start();
                //异步完成调用
                tasks.ContinueWith(parentTask => { Console.WriteLine("所有任务执行完成1"); });
                tasks.Wait();
                //同步完成调用
                Console.WriteLine("所有任务执行完成2");  
            }
    
            static void demo4()
            {
                //i,j,k 的三个循环的调用也是随机的,不是按i,j,k的顺序
                Parallel.Invoke(
                    () =>
                    {
                        //此处的i的输出是并发的,不是从小到大顺序的
                        Parallel.For(0, 5, i =>
                        {
                            Console.WriteLine("{0}\ti={1}", DateTime.Now, i);
                            Thread.Sleep(10);
                        });
                    },
    
                    () =>
                    {
                        //此处的j的输出是并发的,不是从小到大顺序的
                        Parallel.For(0, 5, j =>
                        {
                            Console.WriteLine("{0}\tj={1}", DateTime.Now, j);
                            Thread.Sleep(15);
                        });
                    },
    
                    () => 
                    { 
                        //此处的k的输出是并发的,不是从小到大顺序的
                        Parallel.For(0, 5, k =>
                        {
                            Console.WriteLine("{0}\tk={1}", DateTime.Now, k);
                            Thread.Sleep(13);
                        });  
                    }
                );
            }
        }
  • 相关阅读:
    svn服务器安装
    查看IIS应用程序池的运行状况
    Microsoft Web Farm Framework 和 server Farms
    Subversion 错误信息一览表
    LINUX 时间和日期
    DiskGenius的 “终止位置参数溢出”错误解决方法。
    TortoiseSVN在网盘显示图标的设置
    配置GDB以支持查看stl容器数据
    TortoiseSVN,排除不想提交文件的方法
    win7系统 设置宽带连接网络共享 出现错误 无法启用共享访问 错误代码:0x80004005:未指定错误
  • 原文地址:https://www.cnblogs.com/nanfei/p/2796141.html
Copyright © 2020-2023  润新知