“一心一意”的多线程

来源:互联网 发布:旅行者号 知乎 编辑:程序博客网 时间:2024/05/03 18:33

     多线程——一心一意,一心一意是个人觉得学习了多线程之后,感觉计算机的内部部分实现原理:多线程工作非常专一,分工明确,不能乱来,一心一意只做一件事,但是也很人性化,如果用户想要计算机在同一时间多做几件事,自己就可以再添加,本身计算机还是专一的,只是让CPU在几件事情之间来回工作。     启动任务管理器,点击进程选项,可以看到计算机正在运行的进程,一般一个应用程序对应着一个进程。

     进程,一般包括一个线程,也可以有多个进程。以主线程——UI线程为主,加上添加的多线程。
     计算机执行应用程序原理:CPU不是直接执行某个应用程序——进程,计算机是将一个进程,转化成一个或几个线程,然后再让CPU直接接触线程运行代码,线程起着“中间桥梁”的作用。
     如果让CPU执行一个进程,实际上执行线程,而这个进程又只有一个线程,那么CPU就太浪费了,因此就有了多线程,让CPU发挥其应有的价值,运行尽可能多的线程,让计算机处理速度更快。
     分析单线程出现的问题——如果给一个按钮添加事件,那么用户就无法再拖动窗体,前提是单线程的:
        private void btnSingleThread_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 999999999; i++)
            {
            }
        }
     这是因为主线程——UI线程一心一意地在进行循环,无法再让它干其它事,所以无法拖动窗体。
     多线程的出现能够很好地解决这个问题——让用户自己添加的线程进行循环运算,让主线程——UI线程操作其它事:
     编写多线程并执行步骤:
     S1:编写产生线程所要的方法
     S2:引用命名空间:System Threading;
     S3:实例化Thread类,并传入一个要运行的委托。
     S4:调用Thread实例的Start()方法。
        //循环计数的方法
        void CountTime()
        {
            for (int i = 0; i < 999999999; i++)
            {
            }
        }
        //使用多线程来解决UI线程卡死问题
        private void btnMulTread_Click(object sender, EventArgs e)
        {
            //创建线程对象,传入要线程执行的方法。
            Thread threadFirst = new Thread(CountTime);
            //等同于
            //创建一个委托。上面方法编译器会自动完成委托的创建。
            //ThreadStart ts = new ThreadStart(CountTime);
            //Thread threadFirst = new Thread(ts);


            //启动线程,执行方法。
            threadFirst.Start();
            //这个线程由主线程开启的。
        }
     当程序循环计算的时候,如果此时关闭主程序,实际上后台的另外一个线程仍在运行。这时候需要将这个线程改为后台线程:
     前台线程:只有所有的前台线程都关闭,整个程序才会关闭,如果不设置,默认就是前台线程。
     后台线程:只要所有的前台线程结束,后台线程自动结束。
            //将线程设为后台线程:(当所有的前台线程结束后,后台线程会自动退出。)
            threadFirst.IsBackground = true;
     多线程——方法重入问题:
        //修改文本框内容
        void ChangeTxt()
        {
            for (int i = 0; i < 1000; i++)
            {
                int a = int.Parse(txtFirst.Text);
                Console.WriteLine(Thread.CurrentThread.Name + ",a=" + a + ",i=" + i.ToString());
                a++;
                txtFirst.Text = a.ToString();
            }
        }
        //方法重入问题
        private void btnProblem_Click(object sender, EventArgs e)
        {
            //ChangeTxt()方法由UI线程创建,自己访问可以通过。
            //ChangeTxt()方法此时由非UI线程访问,不被允许访问。
            //在构造方法中Form1()中,加上下面这行代码,将检验关闭。
            //TextBox.CheckForIllegalCrossThreadCalls = false;

            Thread thread = new Thread(ChangeTxt);
            thread.Name = "t1";
            thread.IsBackground = true;
            thread.Start();

            Thread thread2 = new Thread(ChangeTxt);
            thread2.Name = "t2";
            thread2.IsBackground = true;
            thread2.Start();
        }
     上面点击按钮,触发事件,当两个线程同时执行的时候,CPU就会在两个线程之间来回切换,来不及执行后面的自加运算,就切换执行另外一个线程,最终文本框的值肯定不是1000+10000,必定小于2000。
     但是观察输入的i值,当第一个线程结束的时候,对应的i为999,当第二个线程结束的时候,i同样也是999。说明点击按钮事件,主线程会分别给两个线程一个方法,两个方法单独执行,互不影响。
     多线程——执行带参数的方法:
        void ShowTxtName(object name)
        {
            if (name != null)
            {
                MessageBox.Show("name=" + name.ToString());
            }
            else
            {
                MessageBox.Show("null");
            }
        }
        //线程执行带参数的方法
        private void btnThreadWithPara_Click(object sender, EventArgs e)
        {
            //ParameterizedThreadStart pts = new ParameterizedThreadStart(ShowTxtName);
            //Thread thread = new Thread(ShowTxtName);
            //thread.IsBackground = true;
            //thread.Start();

            Thread thread = new Thread(ShowTxtName);
            thread.IsBackground = true;
            thread.Start(txtName.Text);
        }
     多线程——执行带多个参数的方法:
        void ShowTxtName2(object li)
        {
            List<string> list = li as List<string>;
            if (list != null)
            {
                foreach (string s in list)
                {
                    MessageBox.Show(s);
                }
            }
        }
        //执行带多个参数的方法
        private void btnThreadWithManyPara_Click(object sender, EventArgs e)
        {
            Thread thread = new Thread(ShowTxtName2);
            thread.IsBackground = true;
            //执行方法,将参数传过来。
            thread.Start(new List<string>() { "First", "Second", "Third" });
        }
     备注:写于2013年7月31日

0 0
原创粉丝点击