浅解多线程(一)

多线程的相关概念



1.进程:是操作系统结构的基础;是一个正在执行的程序;计算机中正在运行的程序实例;可以分配给处理器并由处理器执行的一个实体;由单一顺序的执行显示,一个当前状态和一组相关的系统资源所描述的活动单元。

2.线程:线程是程序中一个单一的顺序控制流程。是程序执行流的最小单元。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

3.多线程:在单个程序中同时运行多个线程完成不同的工作,称为多线程。



小结:其实更容易理解一点进程与线程的话,可以举这样一个例子:把进程理解成为一个运营着的公司,然而每一个公司员工就可以叫做一个线程。每个公司至少要有一个员工,员工越多,如果你的管理合理的话,公司的运营速度就会越好。这里官味一点话就是说。cpu大部分时间处于空闲时间,浪费了cpu资源,多线程可以让一个程序“同时”处理多个事情,提高效率。



单线程问题演示



创建一个WinForm应用程序,这里出现的问题是,点击按钮后如果在弹出提示框之前,窗体是不能被拖动的。

 private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 10000000000; i++)
            {
                i += 1;
            }
            MessageBox.Show("出现后能拖动,提示没出现之前窗体不能被拖动");
        }

原因:运行这个应用程序的时候,窗体应用程序自带一个叫做UI的线程,这个线程负责窗体界面的移动大小等。如果点击按钮则这个线程就去处理这个循环计算,而放弃了其它操作,故而窗体拖动无响应。这就是单线程带来的问题。

解决办法:使用多线程,我们自己创建线程。把计算代码放入我们自己写的线程中,UI线程就能继续做他的界面响应了。



线程的创建



线程的实现:线程一定是要执行一段代码的,所以要产生一个线程,必须先为该线程写一个方法,这个方法中的代码,就是该线程中要执行的代码,然而启动线程时,是通过委托调用该方法的。线程启动是,调用传过来的委托,委托就会执行相应的方法,从而实现线程执行方法。

 //创建线程
        private void button1_Click(object sender, EventArgs e)
        {
            //ThreadStart是一个无参无返回值的委托。
            ThreadStart ts = new ThreadStart(js);
            //初始化Thread的新实例,并通过构造方法将委托ts做为参数赋初始值。
            Thread td = new Thread(ts);   //需要引入System.Threading命名空间
            //运行委托
            td.Start();
        }
        //创建的线程要执行的函数。
        void js()
        {
            for (int i = 0; i < 1000000000; i++)
            {
                i += 1;
            }
            MessageBox.Show("提示出现前后窗体都能被拖动");
        }

把这个计算写入自己写的线程中,就解决了单线程中的界面无反应缺陷。



小结:创建线程的4个步骤:1.编写线程索要执行的方法。2.引用System.Threading命名空。3.实例化Thread类,并传入一个指向线程所要运行方法的委托。4.调用Start()方法,将该线程标记为可以运行的状态,但具体执行时间由cpu决定。



 方法重入(多个线程执行一个方法)



由于线程可与同属一个进程的其它线程共享进程所拥有的全部资源。

所以多个线程同时执行一个方法的情况是存在的,然而这里不经过处理的话会出现一点问题,线程之间先后争抢资源,致使数据计算结果错乱。

 public partial class 方法重入 : Form
    {
        public 方法重入()
        {
            InitializeComponent();

            //设置TextBox类的这个属性是因为,开启ui线程,
            //微软设置检测不允许其它线程对ui线程的数据进行访问,这里我们把检测关闭,也就允许了其它线程对ui线程数据的访问。
            //如果检测不设置为False,则报错。
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = "0";
            //开启第一个线程,对js方法进行计算
            ThreadStart ts = new ThreadStart(js);
            Thread td = new Thread(ts);
            td.Start();

            //开启第二个线程,对js方法进行计算
            ThreadStart ts1 = new ThreadStart(js);
            Thread td1 = new Thread(ts1);
            td1.Start();
        }
        //多线程要重入的方法。
        void js()
        {
            int a = Convert.ToInt32(textBox1.Text);
            for (int i = 0; i < 2000; i++)
            {
                a++;
                textBox1.Text = a.ToString();
            }
        }
    } 

出错现象:点击按钮后TextBox1中数据为2000+或2000,如果你看到的数据一直是2000说明你的计算机cpu比较牛X,这样的话你想看到不是2000的话,你可以多点击几次试试,真不行的话,代码中给TextBox1赋值为0,换做在界面中给textBox1数值默认值为0试试看。

出错原因:两个进程同时计算这个方法,不相干扰应该每个线程计算的结果都是2000的,但是这里的结果输出却让人以外,原因是第一个两个线程同时计算,并不是同时开始计算,而是根据cpu决定的哪个先开始,哪个后开始,虽然相差时间不多,但后开始的就会取用先开始计算过的数据计算,这样就会导致计算错乱。

解决办法:解决这个的一个简单办法解释给方法加锁,加锁的意思就是第一个线程取用过这个资源完毕后,第二个线程再来取用此资源。形成排队效果。

下面给方法加锁。

//多线程要重入的方法,这里加锁。
        void js()
        {
            lock (this)
            {
                int a = Convert.ToInt32(textBox1.Text);
                for (int i = 0; i < 2000; i++)
                {
                    a++;
                    textBox1.Text = a.ToString();
                }
            }
        }

给方法加过锁后,线程一前一后取用资源,就能避免不可预计的错乱结果,第一个线程计算为2000,第二个线程计算就是从2000开始,这里的结果就为4000。



小结:多线程可以同时运行,提高了cpu的效率,这里的同时并不是同时开始,同时结束,他们的开始是由cpu决定的,时间相差不大,但会有不可预计的计算错乱,这里要注意类似上面例子导致的方法重入问题。



前台线程后台线程



.Net的公用语言运行时能区分两种不同类型的线程:前台线程和后台线程。这两者的区别就是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。

问题:关闭了窗口,消息框还能弹出。

  private void button1_Click(object sender, EventArgs e)
        {
            //开启一个线程,对js方法进行计算
            ThreadStart ts2 = new ThreadStart(js);
            Thread td2 = new Thread(ts2);
            td2.Start();

        }
        void js()
        {
            for (int i = 0; i < 2000000000; i++)  //如果看不出效果这里的2后面多加0
            {
                i++;
            }
            MessageBox.Show("关闭了窗口我还是要出来的!");
        }

原因:.Net环境使用Thread建立线程,线程默认为前台线程。即线程属性IsBackground=false,而前台线程只要有一个在运行则应用程序不关闭,所以知道弹出消息框后应用程序才算关闭。

解决办法:在代码中设置td2.IsBackground=true;



线程执行带参数的方法


 //创建一个执行带参数方法的线程
        private void button1_Click(object sender, EventArgs e)
        {
            //ParameterizedThreadStart这是一个参数类型为object的委托
            ParameterizedThreadStart pts=new ParameterizedThreadStart(SayHello);
            Thread td2 = new Thread(pts);
            td2.Start("张三");  //参数值先入这里
        }
        void SayHello(object name)
        {
            MessageBox.Show("你好,"+name.ToString()+"!");
        } 



线程执行带多参数的方法



其实还是带一参数的方法,只不过是利用参数类型为object的好处,这里将类型传为list类型,貌似多参。

        //创建一个执行带多个参数的方法线程
        private void button1_Click(object sender, EventArgs e)
        {
            List<string> list = new List<string> { "张三", "李四", "王五" };
            //ParameterizedThreadStart这是一个参数类型为object的委托
            ParameterizedThreadStart pts=new ParameterizedThreadStart(SayHello);
            Thread td2 = new Thread(pts);
            td2.Start(list);  //参数值先入这里
        }
        void SayHello(object list)
        {
            List<string> lt = list as List<string>;
            for (int i = 0; i < lt.Count; i++)
            {
                MessageBox.Show("你好," + lt[i].ToString() + "!");
            }
        } 




总结:看到这里相信对多线程应该有一个初步的了解了,我就不说了。

************转载:http://www.cnblogs.com/knowledgesea/archive/2012/11/22/2780651.html

原文地址:https://www.cnblogs.com/linybo/p/10093473.html

时间: 2024-10-21 06:40:05

浅解多线程(一)的相关文章

浅解多线程(二)之和尚们的那些事儿

浅解多线程(一)之线程入门起步 本文链接 确定多线程的结束时间,thread的IsAlive属性 线程优先级,thread的ThreadPriority属性 线程通信之Monitor类 线程排队之Join 多线程互斥锁Mutex 信号量semaphore 确定多线程的结束时间,thread的IsAlive属性 在多个线程运行的背景下,了解线程什么时候结束,什么时候停止是很有必要的. 案例:老和尚念经计时,2本经书,2个和尚念,一人一本,不能撕破,最短时间念完,问老和尚们念完经书最短需要多长时间.

byte和int的浅解

1.byte范围为什么是(-128~127)? --byte是8位 --这里定义2种8位展现形式:1,符号形式(第一眼看符号位,判断正负,然后计算剩下7位的数值).2,存储形式(内存中都是补码存储) --想要知道一个数在内存中如何存储?真值 >> 符号形式 >> 补码 >> 存储形式 --示例1: +8(真值) +8(符号形式):0000 1000,//真值"+8",因为是"+",所以将第一位定义为0,因为值是"8&qu

[从玩游戏来理解编程]关于面向对象编程的浅解(1)

我最近在玩星际争霸2,感觉到面向对象真是太重要了.有三个种族,每个种族有自己的兵种,一个兵种就是一个类,而且他们的父类都是一个类. 每个单位都有自己的属性和技能,之前学习的c语言是面向过程的,慢慢的也理解到了面向对象在某些地方的重要性. 之前都是在学习算法,实现上用的c语言,看不出来到底有什么区别,反而在用c来的更简洁和更快,最近慢慢的接触到小项目之类的什么的就慢慢感觉到面向对象的重要性. 最近在看一本书叫<making games with python and pygame>,这本书很好,

详解多线程MT和多线程MD的区别

这段时间司在招实习生,而不管是远程的电话面试或者是实际现场面试中领导都喜欢问你这个问题,但是可惜的是能很好答上来的人很少.后来发现不管是应届的实习生,甚至有些实际参加工作几年的人也未必真的了解这个问题.今天想写一篇详解,希望对广大程序员有一定的帮助. 区别1:全局堆句柄不一样. 网上有一个说法,就是一个线程一个栈,一个模块一个堆.前者很容易有理解,每个线程创建的时候在CreateThread中都能制定默认栈大小,只是很多情况下都取了默认值.而一个模块一个堆呢?其实很简单测试,如果是一个多线程MT

软考之路(1)——浅解网络基础知识

对网络这一块的基础知识理解如下,以图文并茂的形式展出,便于分析和理解.解析与图如下: 物理层: 功能: 提供为建立.维护和拆除物理链路所需的机械.电气.功能和规程的特性: 提供有关在传输介质上传输非结构的位流及物理链路故障检测指示: 为数据链路层提供一个物理连接,以及他们的机械.电气.功能和过程性.如规定使用电缆和接头的类型,传送信号的电压.在这一层,数据还没有被组织,仅作为原始的位流或电气电压处理,单位是位. 物理链路: 这里多次出现物理链路,简单解释物理链路:一条无源的点到点的物理线路段,中

面试-1-C#浅解

C#浅解众所周知c#是微软推出的一款完全没面向对象的编程语言,那么对象是什么?在现实生活中人们一提到对象首先想到的就是"情侣"!但是在我们的程序中对象是什么? 在程序中个能够区别于其他事物的独立个体我们称它为对象他是类的一个实例.那么现在问题来了 ,你说对象是类的实例.那类又是什么?好 在程序中类是多个对象的统称他是对象的模版规定了对象所具有的行为(方法)和静态特征(字段).这是有人可能会问"是先有类还是先有对象?"关于这个问题我们就要分情况讨论了第一种情况:在现实

进行概念详解 多线程上篇(二)

操作系统是程序与硬件交互的中间层,现代操作系统将程序的一次执行抽象为进程和线程的概念. 进程作为资源分配的基本单位,线程作为执行的基本单位. 进程和线程其实就是操作系统程序本身实现控制一个程序运行的数据项描述 所有的程序都是面向语言进行开发的,而语言本身是面向操作系统的,线程是操作系统对程序一次运行的抽象 所以,所有的多线程编程模型,必然遵从操作系统的大逻辑,必然是符合操作系统的对线程的抽象概念,操作系统在抽象之上提供了API供应用程序调用 简言之,应用程序的底层是借助于操作系统来完成多线程编程

从最大似然到EM算法浅解

原文在这里 机器学习十大算法之一:EM算法.能评得上十大之一,让人听起来觉得挺NB的.什么是NB啊,我们一般说某个人很NB,是因为他能解决一些别人解决不了的问题.神为什么是神,因为神能做很多人做不了的事.那么EM算法能解决什么问题呢?或者说EM算法是因为什么而来到这个世界上,还吸引了那么多世人的目光. 我希望自己能通俗地把它理解或者说明白,但是,EM这个问题感觉真的不太好用通俗的语言去说明白,因为它很简单,又很复杂.简单在于它的思想,简单在于其仅包含了两个步骤就能完成强大的功能,复杂在于它的数学

python趣味详解多线程

python3的多线程很多人无法理解是怎么运行的,因此本文从程序猿的日常生活出发,写了一个由浅入深的多线程教程,这样子大家就不会觉得陌生了,多线程真的很简单很简单! 假设我是一个程序猿,我想听歌,但是我又要打码,所以有: 我听完歌就去打码: 1 #!/usr/bin/python3.4 2 # -*- coding: utf-8 -*- 3 4 import time 5 6 def matter1(music): 7 print("我想听这些歌") 8 9 for i in rang