C#多线程备忘

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);
                    });  
                }
            );
        }
    }

 

posted on 2012-11-30 14:01  空明流光  阅读(279)  评论(0编辑  收藏  举报

导航