• 简单的C#线程开发实例(隔一秒改变一下Label的Text)


    要实现的效果:点击按纽,窗口上的label上出现1~100数字的变化。

    第一个实例(把窗口上的label上文字改成0):

    using System;

    using System.Windows.Forms;

    namespace ThreadTest

    {    

       public partial class Form1 : Form    

      {        

        public Form1(){InitializeComponent();}

               private void Form1_Load(object sender, EventArgs e){label1.Text = "0";}    
      }
    }
    这个是最简单的实例,很容易。
    第二个实例(点击button,循环显示0动态变化到100数字):
    using System;
    using System.Windows.Forms;
    namespace ThreadTest
    {    
      public partial class Form1 : Form    
      {        
        public Form1(){InitializeComponent();}
               private void Form1_Load(object sender, EventArgs e){label1.Text = "0";}
               private void button1_Click(object sender, EventArgs e)
        {
          for(int i=0;i<101;i++){label1.Text = i.ToString();}
        }    
      }
    }
    运行一下,点击一下button1,没有看到0~100动态变化,就直接到了100了。 原因:因为你的处理器速度太快了,就只能看到最后的结果。那么,怎样才能看到中间过程呢?
    我们先用函数的方式来实现上面的功能,写个名为run的函数: private void run() {     for(int i=0;i<101;i++){         label1.Text = i.ToString();     } }
    这样就可以直接调用run函数实现功能了,而不用在事件函数内写代码。
    第三个实例(使用函数):
    using System;
    using System.Windows.Forms;
    namespace ThreadTest
    {    
      public partial class Form1 : Form    
      {        
        public Form1(){InitializeComponent();}
               private void Form1_Load(object sender, EventArgs e){label1.Text = "0";} 
               private void run() {     for(int i=0;i<101;i++){         label1.Text = i.ToString();     } }   
               private void button1_Click(object sender, EventArgs e){run();} 
       }
    }
    这里就需要在循环过程中加延时了,假定我们每隔1s的延时,lable1的值增加1,方法有很多。
    首先我们用一个timer来实现延时。 添加一个timer, 命名为timer1,在timer1的tick事件内添加语句,改变label1的值。(Tick事件是每经过指定时间间隔后被触发)。
    第四个实例(使用timer),实现每隔1s的延时,lable1的值增加1,以达到动态变化的效果:
    using System;
    using System.Windows.Forms;
    namespace ThreadTest
    {    
      public partial class Form1 : Form    
      {        
         int i;          //全局变量
              public Form1(){InitializeComponent();}
                private void Form1_Load(object sender, EventArgs e){label1.Text = "0";} 
        private void run()
        {     
          i = 0;     
          timer1.Interval = 1000; //设置timer1的间隔时间    
          timer1.Start(); //启动timer1        
        }
        private void timer1_Tick(object sender, EventArgs e) 
              {
                   i++;            
           if (i > 100) {timer1.Stop();}            
           label1.Text = i.ToString();        
        }    
                private void button1_Click(object sender, EventArgs e) {run();}
       }
    }
    我们运行一下,能够看到0~100循环的过程了。
    以上是我们平常的做法,让label动态变化的效果,下面我们开始使用线程来实现上面的功能。
    由于要使用多线程,我们需要引用using System.Threading;
    通过下面的语句就定义一个名为thread1的线程 private Thread thread1;
    和定义函数极为相似,定义线程之后,就要进行实例化: thread1 = new Thread(new ThreadStart(run));
    这个语句的意思就是实例化thread1并将run函数设定为thread1的入口函数(大概意思就是,让run函数在线程thread1上执行)。
    创建线程就算完成了,那么怎么运行线程呢? 其实和启动timer1是类似的,thread1.Start();就运行了我们创建的线程thread1。
    既然我们创建了线程,那么在关闭窗口的时候,就要撤消线程。添加FormClosing事件,在事件内部写如撤消线程的代码:
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
       if (thread1.IsAlive) //判断thread1是否存在,不能撤消一个不存在的线程,否则会引发异常
       { thread1.Abort(); //撤消thread1 }
    }
    这样才算大功告成,整理的代码如下:(在第三个实例的基础上加以改动)。
    第五个实例:
    using System;
    using System.Threading;
    using System.Windows.Forms;

    namespace ThreadTest

    {    

      public partial class Form1 : Form    

       {        

          private Thread thread1;

                public Form1(){InitializeComponent();}

                private void Form1_Load(object sender, EventArgs e){label1.Text = "0";}

                private void button1_Click(object sender, EventArgs e){thread1 = new Thread(new ThreadStart(run));thread1.Start();}

                private void run(){for (int i = 0; i < 101; i++){label1.Text = i.ToString();}}

                private void Form1_FormClosing(object sender, FormClosingEventArgs e){if (thread1.IsAlive){thread1.Abort();}}    
      }
    }
    运行一下,按button1,出错了,怎么回事呢?
    看看出错原因,是在run函数内的label1.Text = i.ToString();语句上出的错,没错啊,语法正确啊。解释一下,出错的原因是为了保护数据的安全所以不能跨线程调用控件,而label1.Text = i.ToString();句则是在线程thread1上面调用主线程的控件,肯定会出错的!怎么办呢?用委托啊,我的理解就是,线程thread1不能调用主线程的lable1,所以,就委托主线程来改变lable1的值。 首先看一个例子:(从例3改写)(并不创建线程,仅有主线程) 创建一个函数,用来设置lable1的值;

    private void set_lableText(string s) { label1.Text = s; } 当需要改变lable1的值时,就调用它,并传递要改变的值。

    第六个实例:

    using System;

    using System.Windows.Forms;

    namespace ThreadTest

    {    

      public partial class Form1 : Form    

      {        

        public Form1(){InitializeComponent();}

             private void Form1_Load(object sender, EventArgs e){label1.Text = "0";}

               private void button1_Click(object sender, EventArgs e){run();    //调用run函数}

               private void run(){for(int i=0;i<101;i++){set_lableText( i.ToString() );}}

               private void set_lableText(string s){label1.Text = s;}    
       }
    }
    实现的功能与第三个实例是一样的,只是,增加了一个函数。
    到这里,需要了解一下委托这个东西,我们就需要委托主线程调用函数set_lableText(string s);来改变lable1的值。

    首先声明一个委托: delegate void set_Text(string s);

    创建一个全局委托变量: set_Text Set_Text;

    进行实例化: Set_Text = new set_Text(set_lableText); //括号内的set_lableText是委托要调用的函数(也就是例6写的set_lableText(string s);函数)

    现在,就剩下调用委托了,怎么调用委托呢?很简单。 同过Invoke来调用,语句如下:

    label1.Invoke(Set_Text, new object[] { i.ToString() }); //Set_Text是调用的委托,object[]则是我们要传递的参数

    整理代码如下,第七个实例:

    using System;

    using System.Threading;

    using System.Windows.Forms;

    namespace ThreadTest

    {    

      public partial class Form1 : Form    

      {        

          private Thread thread1; //定义线程

              delegate void set_Text(string s); //定义委托

              set_Text Set_Text; //定义委托变更

              public Form1(){InitializeComponent();}

              private void Form1_Load(object sender, EventArgs e){label1.Text = "0";       Set_Text = new set_Text(set_lableText); //实例化}

              private void button1_Click(object sender, EventArgs e){thread1 = new Thread(new ThreadStart(run));       thread1.Start();}

              private void set_lableText(string s){label1.Text = s;}//主线程调用的函数

              private void run()

         {

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

            {                

              label1.Invoke(Set_Text, new object[] { i.ToString() }); //通过调用委托,来改变lable1的值                

              Thread.Sleep(1000); //线程休眠时间,单位是ms            

            }        

          }

               private void Form1_FormClosing(object sender, FormClosingEventArgs e)        
         {            
            if (thread1.IsAlive) //判断thread1是否存在,不能撤消一个不存在的线程,否则会引发异常            
            {thread1.Abort(); //撤消thread1}
               }
        }
    }
    这样,一个简单的多线程程序就算完成了。
  • 相关阅读:
    OpenMP vs WinSxS
    JIT, dynarec and binary translation
    VC++2010 bug
    控制和释放共享内存块
    分配和释放信号量
    代码列表5.1 (shm.c) 尝试共享内存
    绑定和脱离
    信号量
    每个字段动态添加一个随机数
    最近做了一个红底鞋类电商网站
  • 原文地址:https://www.cnblogs.com/yaosuc/p/4735942.html
Copyright © 2020-2023  润新知