码迷,mamicode.com
首页 > 编程语言 > 详细

C#多线程

时间:2017-05-16 14:59:50      阅读:234      评论:0      收藏:0      [点我收藏+]

标签:com   入口   ati   log   div   传递参数   sys   tar   建立   

多线程简单来说就是让计算机进行“一心多用”,不过此处一心多用并不是真正的一心多用,只是在不同的时间片段(极短的时间片段内)分别执行不同的操作,但在单位时间片段内饰一心一用。简单举个例子,周伯通让小龙女学习左右互搏,让她一手画方一手画圆,做到一心两用。那我们来简单分析一下,如果不是同时结束呢,我们先这样来,左手先画四分之一圆,完成后右手再画正方形的一条边,然后依次类推,知道方圆均画完。这样属于两个手分别操作,那么我们进一步细分,左后先画八分之一圆,右手再画八分之一正方形,当然这样还是两个手分别操作,那么我们整个圆和方形分成一百步画完呢,假如分成一千步呢?分成一千步即使每一步都是单独的在画圆或者或方,但是总体上方圆基本同时在进行。这就是多线程所展现给我们的,但是多线程的意义就是当某一线程阻塞了,不会导致整个程序等待。加入我们只会用一只手画方圆,先画圆后画方,那么在画圆的过程中加入手抽筋了,那我们都要在等待手恢复,如果一手画方一手画圆,那么左手即使抽筋了,只是影响画圆而不影响右手画方。这就是多线程的意义。下面讲解三种最基本的开启线程方法,讲解过程中为了分别讲解,只引用了部分代码,最后会给出完整代码,建议可以边运行边看分步讲解。

1、引入命名空间System.Threading,最基本在简洁的方法ThreadStart/ParameterizedThreadStart,前者不带参数,后者可以给方法传递一个参数(带参数的方法入口参数必须为object类型),但是最基本的方法,开启线程比较随意,容易混乱而且开启过多线程也会影响性能。开启线程不过是在主程序运行或者其他方法运行时,开启其他方法,既然开启其他就必然用得到委托,本质上还是向thread类中传递要开启的方法,具体开启线程有thread类完成。开启线程方法:

(一)定要开启的方法

        static void AsyncDemo()//无参数的方法
        {
            for(int i=0;i<=10;i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Async thread : " + i);
            }
        }
        static void AsyncDemo(object obj)//有参数的方法
        {
            string _obj = (string)obj;
            Console.WriteLine(_obj);
            for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Async thread : " + i);
            }
        }

(二)开启线程

            //Thread thread = new Thread(new ThreadStart(AsyncDemo));
            //thread.Start();
            string para = "Hello World!";
            Thread thread = new Thread(new ParameterizedThreadStart(AsyncDemo));
            thread.Start(para);

(三)主程序的运行

           //主程序
            for (int i=0;i<=10;i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Main thread : " + i);
            }

本例子通过两个for语句来分别假定主程序方法和线程方法,如果不用线程,会一个循环执行完在执行另一个循环,如果没有Thread.Sleep(100)则体现不出同时运行的效果,因为就是在极短的时间片段内,每一个循环都可以执行完,所以为了达到效果,让每一个都暂停0.1s。

2、在程序中随意开启线程会影响程序的质量,所以C#提供了线程池来管理线程,即通过QueueUserWorkItem来开启线程,他有两个重载,可以传递参数给开启线程的方法。开启线程的方法还是采用1、中方法,线程开启如下:

            string str = "Hello World!";
            ThreadPool.SetMaxThreads(1000, 1000);//定义处于活动状态的线程池的请求数目
            ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncDemo),str);
           // ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncDemo));//无参数的方法

3、以上两种方法都没有返回值,若一个方法有返回值,则需要其他方法来实现。开启线程本质上还是通过委托传递一个方法(函数),而委托也为我们提供了相应开启线程的方法。当我们定义好委托以后,在码代码的时候平台会自动给我们提示它可能存在的方法,其中BeginInvoke(name, null, null)方法就是来开启线程,第一个参数为方法所需要的入口参数,第二个为回调函数,其参数必须为一个IAsyncResult 接口,第三个为 为回调函数传入的参数。后两个参数可以为空,它返回一个IAsyncResult类型的接口,通过此接口传入EndInvoke(result)方法即可获取返回值。下面为具体步骤:  

(一)建立委托

public delegate string Mydeletegate(string str);

(二)定义相关方法

        static string AsyncDemo(string obj)
        {
            string _obj = (string)obj;
            Console.WriteLine(_obj);
            for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Async thread : " + i);
            }
            return "Hello " + obj;
        }

(三)委托指向方法并开启线程

IAsyncResult result = de.BeginInvoke(name, null, null);
 for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Main thread : " + i);
            }

            string redata = de.EndInvoke(result);
Console.WriteLine(redata);

但是此方法会存在一个问题,即如果把上述代码中的redata那一语句放在for循环之前,则会先执行型委托指向的方法的循环,后执行主程序(可以自行测试),因为主程序在等待执行完redata=。。。。后再执行for语句,所以可以充分利用接口IAsyncResult提供的方法或者字段。也可以采用BeginInvoke方法的第二个参数,回调函数,即把EndInvoke方法放入回调函数中,本例的回调函数为Completed。回调函数如下:

        static void Completed(IAsyncResult res)
        {
            string str = (string)res.AsyncState;
            AsyncResult _res = (AsyncResult)res;
            Mydeletegate de1 = (Mydeletegate)_res.AsyncDelegate;
            string data = de1.EndInvoke(res);
            Console.WriteLine(data);
            Console.WriteLine(str);
        }

对相关参数进行一下解释:通过接口中的AsyncState可以获取异步操作传入的信息,即BeginInvoke的第三个参数,为object类型的,要转化成所用的类型。我们要在此函数中完成EndInvoke就需要获取BeginInvoke的委托,查看元数据可以知道AsyncResult 继承了IAsyncResult 接口,AsyncResult中的AsyncDelegate属性可以获取相关委托,所以先把传入的IAsyncResult 转化为AsyncResult 类型,在通过AsyncDelegate获取到委托(其为object类型,需要转化为委托类型),然后调用EndInvoke方法,获取返回值, 主程序如下:

de.BeginInvoke(name, new AsyncCallback(Completed), index);

            for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Main thread : " + i);
            }

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

在最后附上三种方法的完整程序,这三种方法为最基本的方法,在以后不管是网络请求还是文件I/O的异步编程都与委托类方法一样。

 

方法1的完整代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MyThread
{
    class Program
    {
        static void AsyncDemo()//无参数的方法
        {
            for(int i=0;i<=10;i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Async thread : " + i);
            }
        }
        static void AsyncDemo(object obj)//有参数的方法
        {
            string _obj = (string)obj;
            Console.WriteLine(_obj);
            for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Async thread : " + i);
            }
        }
        static void Main(string[] args)
        {
            //无参数方法
            //Thread thread = new Thread(new ThreadStart(AsyncDemo));
            //thread.Start();
            string para = "Hello World!";
            Thread thread = new Thread(new ParameterizedThreadStart(AsyncDemo));
            thread.Start(para);

            //主程序
            for (int i=0;i<=10;i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Main thread : " + i);
            }
            Console.ReadKey();
        }
    }
}

方法2的完整代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ThreadPoolTest
{
    class Program
    {
        static void AsyncDemo()
        {
            for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Async thread : " + i);
            }
        }
        static void AsyncDemo(object obj)
        {
            string _obj = (string)obj;
            Console.WriteLine(_obj);
            for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Async thread : " + i);
            }
        }
        static void Main(string[] args)
        {
            string str = "Hello World!";
            ThreadPool.SetMaxThreads(1000, 1000);//定义处于活动状态的线程池的请求数目
            ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncDemo),str);
           // ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncDemo));//无参数的方法


            for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Main thread : " + i);
            }
            Console.ReadKey();
        }
    }
}

 

方法3的完整代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace Deletegatetest
{
    public delegate string Mydeletegate(string str);

    class Program
    {

        static string AsyncDemo(string obj)
        {
            string _obj = (string)obj;
            Console.WriteLine(_obj);
            for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Async thread : " + i);
            }
            return "Hello " + obj;
        }
        //回调函数
        static void Completed(IAsyncResult res)
        {
            string str = (string)res.AsyncState;
            AsyncResult _res = (AsyncResult)res;
            Mydeletegate de1 = (Mydeletegate)_res.AsyncDelegate;
            string data = de1.EndInvoke(res);
            Console.WriteLine(data);
            Console.WriteLine(str);
        }

        static void Main(string[] args)
        {
            string name = "Andy";
            string index = "Index!";
            Mydeletegate de = new Mydeletegate(AsyncDemo);
            
            //IAsyncResult result = de.BeginInvoke(name, null, null);
            de.BeginInvoke(name, new AsyncCallback(Completed), index);

            for (int i = 0; i <= 10; i++)
            {
                Thread.Sleep(100);
                Console.WriteLine("Main thread : " + i);
            }

            //string redata = de.EndInvoke(result);
            //Console.WriteLine(redata);

            //for (int i = 0; i <= 10; i++)
            //{
            //    Thread.Sleep(100);
            //    Console.WriteLine("Main thread : " + i);
            //}
            Console.ReadKey();
        }
    }
}

 

C#多线程

标签:com   入口   ati   log   div   传递参数   sys   tar   建立   

原文地址:http://www.cnblogs.com/llstart-new0201/p/6860733.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!