多线程基础

 

多线程的好处在于可以提高CPU的利用率——任何一个程序员都不希望自己的程序很多时候没事可干,在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。

     我们可以举一个例子描述多线程。假设有一个公司,公司里有很多各司其职的职员,那么我们可以认为这个正常运作的公司就是一个进程,而公司里的职员就是线程。一个公司至少得有一个职员吧,同理,一个进程至少包含一个线程。在公司里,你可以使一个职员干所有的事,但这样的话效率很显然是高不起来的,一个人的公司也不可能做大;一个程序中也可以只用一个线程去做事,就象一个人的公司一样,效率很低,如果做大程序,效率更低——事实上现在几乎没有单线程的商业软件。所以我们需要多个人同时做多件事情,但是公司的职员越多,老板就得发越多的薪水给他们,还得耗费大量精力去管理他们,协调他们之间的矛盾和利益;程序也是如此,线程越多耗费的资源也越多,需要CPU时间去跟踪线程,还得解决诸如死锁,同步等问题。总之,如果你想让你的公司做大做强,你就得多几个员工;同理,如果你不想让你的程序显得稚气,就在你的程序里引入多线程吧!

一、为什么要多线程?

我们先从一个例子出发:

static void Main(string[] args)

        {

            ShowNum();

        }

        private static void ShowNum()

        {

            for (int i = 0; i < 500; i++)

            {

                Console.WriteLine("A"+i.ToString());

            }

       }

如上程序,在输出的过程中是不能再做任何事情的,必须等待他执行完成才可以进行下个任务,这就是我们所谓的“单线程”。那怎么才可以同时执行2件,甚至多件事情,而且互相不耽误?这就是我们的目标——多线程

想要同时执行多个任务,那还不简单?多写几个方法不就OK

下来,我们改进上面的程序:

static void Main(string[] args)

        {

            ShowNum();

            ShowNumToo();

        }

        private static void ShowNum()

        {

            for (int i = 0; i < 500; i++)

            {

                Console.WriteLine("A"+i.ToString());

            }

        }

        private static void ShowNumToo()

        {

            for (int i = 0; i < 500; i++)

            {

                Console.WriteLine("B" + i.ToString());

            }

        }

从运行的结果我们发现,并不是我们想要的,他总是把第一个方法执行完毕才会执行第二个方法,如此,如果第一个方法在执行的时候出现停顿,那么第二个方法就得一直等待,造成效率低下,资源浪费,要解决这个问题,就必须使用多线程。

二、如何多线程


使用多线程,首先得明白

static void Main(string[] args)

        {

            Thread t = new Thread(new ThreadStart(ShowNum));

            t.Start();

            Thread ttoo = new Thread(new ThreadStart(ShowNumToo));

            ttoo.Start();

        }

        private static void ShowNum()

        {

            for (int i = 0; i < 500; i++)

            {

                Console.WriteLine("A"+i.ToString());

            }

        }

        private static void ShowNumToo()

        {

            for (int i = 0; i < 500; i++)

            {

                Console.WriteLine("B" + i.ToString());

            }

        }

这次我们发现在输出的时候,是2个结果交替输出的,说明了2个方法在同时运行,我们的目标基本达到。那他们的原理又是什么呢?

首先,我们在上面引入了一个命名空间,叫

using System.Threading;

然后创建了2个线程,tttoo,然后给他们分别传入2个委托,表示线程开始执行时要调用的方法。这样系统就为他们分配了2个线程,他们可以独立运行。

好了,还有一些其他的操作或者属性了之类的,暂时不做详述。上面全部分析的是控制台程序,如果要转到桌面开发又该怎么处理?处理方式是否一样?

三、“线程间操作无效”的问题

如新建一个windows应用程序,在界面放置一个按钮,添加点击事件,代码如:

private void button1_Click(object sender, EventArgs e)

        {

            Thread t = new Thread(new ThreadStart(Shows));

            t.Start();

        }

再添加一个方法,实现给界面的文本框赋值:

public void Shows()

        {

            this.textBox1.Text = DateTime.Now.ToString();

        }

单击按钮,我们发现情况并不像我们想像的那样定时更新文本框的时间,而是出现异常,异常信息如:“线程间操作无效: 从不是创建控件“textBox1”的线程访问它”。原因其实很简单,控件不是由我们的线程创建,他的生命周期也不由我们的线程控制,所以.Net是不允许这样操作的,其实也是为了操作安全。

那怎么解决这个问题呢?

经过查询MSDN:对 Windows 窗体控件进行线程安全调用

只需要按照下面步骤即可:

1.         查询控件的 InvokeRequired 属性。

2.         如果 InvokeRequired 返回 true,则使用实际调用控件的委托来调用 Invoke

3.         如果 InvokeRequired 返回 false,则直接调用控件。
注:
InvokeRequired
表示当前线程不是创建控件的线程时为true,意思是其它线程需要访问控件,那么得声明一个委托,调用invoke来转给控件进行处理,当他的值为false时,说明访问的线程就是创建自己的线程当然可以直接操作。简单的说,如果有两个线程,Thread AThread B,并且有一个Control c,是在Thread A里面new的。那么在Thread A里面运行的任何方法调用c.InvokeRequired都会返回false。相反,如果在Thread B里面运行的任何方法调用c.InvokeRequired都会返回true
Invoke的意思是在拥有此控件的基础窗口句柄的线程上执行指定的委托

delegate void SetTextCallback(string text);

        private void button1_Click(object sender, EventArgs e)

        {

            Thread t = new Thread(new ThreadStart(Shows));

            t.Start();

        }

        public void Shows()

        {

            while (true)

            {

                SetText(DateTime.Now.ToString());

            }

        }

        private void SetText(string text)

        {

            if (this.textBox1.InvokeRequired)

            {

                SetTextCallback d = new SetTextCallback(SetText);

                this.Invoke(d, new object[] { text });

            }

            else

            {

                this.textBox1.Text = text;

            }

        }

由此问题解决。

posted @ 2010-06-20 13:19  石曼迪  Views(387)  Comments(0Edit  收藏  举报
瓴域建设-环保事业中心