多线程初学

来源:互联网 发布:怎么购买淘宝小号 编辑:程序博客网 时间:2024/05/19 22:06

多线程的概念:

一个正在运行的程序就是一个进程,一个进程至少有一个线程,同一个进程中的多个线程之间可以“并发”执行。
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。

多线程的优缺点:

多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务(代码),也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。这样可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。

而不利的地方就是多线程需要占用内存,线程越多占用的内存就越多。并发执行时控制太复杂,可能造成无法预料的BUG,而且竞争共享资源。


.net中如何实现多线程:

线程肯定也是要执行一段代码的。所有要产生一个线程,必须先为该线程写一个方法,这个方法中的代码就是该线程运行多要执行的代码。

线程启动时,通过委托调用该方法。

(线程启动时,调用传过来的委托,委托就会执行相应的方法,实现线程执行方法)


产生一个线程的4步骤:

编写产生线程所要执行的方法

引用System.Threading命名空间

       实例化Thread类,并传入一个指向线程所要运行方法的委托(这时候这个线程已经产生,但是还没有运行)

       调用Thread实例的Start方法,标记该线程可以被CPU执行了,但具体执行时间由CPU决定。


前台线程和后台线程:

前台线程:只有所有的前台线程都关闭才能完成程序关闭。

后台线程:只要所有的前台线程结束,后台线程自动结束。

程序中通过设置线程的IsBackground属性为true,将线程设置为后台线程。 


下面为一个例子

        public Form1()        {            InitializeComponent();            TextBox.CheckForIllegalCrossThreadCalls = false;        }        void Count999999999()//让计算机从0数到999999999,计算时间        {            DateTime begin = DateTime.Now;            for (int i = 0; i <= 999999999; i++)            {            }            TimeSpan span = begin.Subtract(DateTime.Now);            MessageBox.Show("走完了~"+span);        }        private void Btn_singlethread_Click(object sender, EventArgs e)//使用单线程计数        {            Count999999999();        }        private void Btn_multithreads_Click(object sender, EventArgs e)//使用多线程        {            Thread multigo = new Thread(Count999999999);//创建多线程,并写入调用的函数            multigo.IsBackground = true;//讲多线程设为后台线程            multigo.Start();//启用多线程        }

这时可以看到,在单线程执行时,UI不能响应用户操作,而使用多线程时却可以。这是因为创建负责计数的线程替UI线程完成了计数功能,这样UI线程就能空出来完成自己的功能了。

为了说明多线程在同时执行时的不确定性,我们来引入下面一个例子,这个例子也是我在面试时遇到的一道题。

        Thread THWriteab = null;        Thread THWritecd = null;        private void Btn_writeletter_Click(object sender, EventArgs e)//开始按钮        {            THWriteab = new Thread(WriteAB);            THWriteab.IsBackground = true;            THWriteab.Start();            THWritecd = new Thread(Writecd);            THWritecd.IsBackground = true;            THWritecd.Start();        }        public void WriteAB()//函数用来输出AB        {            while (true)            {                textBox1.AppendText("AB");            }        }        public void Writecd()//函数用来输出cd        {            while (true)            {                textBox1.AppendText("cd");            }        }        private void btnWriteStop_Click(object sender, EventArgs e)//停止进程的按钮        {            THWriteab.Abort();//进程<span style="font-family:Arial,Helvetica,sans-serif">THWriteab停止</span>            THWritecd.Abort();//进程<span style="font-family:Arial,Helvetica,sans-serif">THWritecd停止</span>        }


造成这种情况的原因,是线程在执行过程中可能随时睡眠,并由CPU切换到下一进程继续执行。在本例中,可能刚输出一个A,然后线程睡眠,CPU跳到输出CD的进程中,在输出了CD之后又跳回输出B。(CPU在同一时间只能执行一个线程,多核CPU可以同时执行多个)


线程的同步策略:

当一个方法被应用程序中多个线程访问时,由于多个线程间的并发访问,会使调用方法后的结果不可预测。一种可行的线程同步策略是使用Monitor类和Lock关键字。

(1)       Monitor类用于同步代码区,其思想是首先使用Monitor.Enter()方法获得一个锁,然后使用Monitor.Exit()方法释放该锁。一个线程一旦获得重要代码区的锁,其他线程就要等到该锁被释放后才能使用该代码区。代码如下:

        public void ShowData1(string data)        {            Monitor.Enter(this);        //加上monito锁            for (int i=0; i < 100; i++)   //重要代码区            {                Console.WriteLine(data);            }            Monitor.Exit(this);         //施放monitor锁        }

(2)       使用Lock关键字同样可以获得一个Monitor锁。只需要简单的用lock语句将需要同步的代码括起来,括号表示受保护代码的起始点和终止点。代码如下:

        public void ShowData2(string data)        {            lock (this)  //lock语句            {                for (int i = 0; i < 100; i++)   //重要代码区                {                    Console.WriteLine(data);                }                Monitor.Exit(this);            }        }





原创粉丝点击