线程的启动(转)

目录

C#多线程编程(1):线程的启动

1、不带参数的启动方式

2、带参数的启动方法

3、以类的实例作为参数

4、把Thread要处理的业务代码放在一个单独的类中

C#多线程编程(1):线程的启动

在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动时要运行的方法。

在.net中提供了两种启动线程的方式,一种是不带参数的启动方式,另一种是带参数的启动的方式。

1、不带参数的启动方式

如果启动参数时无需其它额外的信息,可以使用ThreadStart来实例化Thread,如下面的代码:

using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace StartThread
{
 class Program
    {
        int interval = 200;
        static void Main(string[] args)
        {
            Program p = new Program();
            //不带参数的启动方法

            Thread nonParameterThread = new Thread(new ThreadStart(p.NonParameterRun));
            nonParameterThread.Start();
        }

        /// <summary>
        /// 不带参数的启动方法
        /// </summary>
        public void NonParameterRun()
        {
            for (int i = 0; i < 10; i++)
            {
            Console.WriteLine("系统当前时间毫秒值:" +DateTime.Now.Millisecond.ToString());
        Thread.Sleep(interval);//让线程暂停
            }
            Console.Read();
        }
}
}

程序的运行效果我们不用运行也会知道,那就是在循环中将系统当前时间的毫秒部分输出出来,在每次输出之后会将当前线程暂停一下,直到10次之后运行完毕,终止线程的执行。

在上面的代码中我们是通过定义全局变量的方法来指定线程暂停间隔,按照这种方法,假如要运行10个线程,每个线程的暂停间隔不一样的话,就需要定义10个全局变量,虽然最终不影响系统的运行效果,但是总觉得不是太爽。

有没有比较简单一点的办法呢?有!那就是使用带参数的启动方法。

 

2、带参数的启动方法

如果要在实例化线程时要带一些参数,就不能用ThreadStart委托作为构造函数的参数来实例化Thread了,而要ParameterizedThreadStart委托,和ThreadStart一样的是它也是线程启动时要执行的方法,和ThreadStart不同的是,它在实例化时可以用一个带有一个Object参数的方法作为构造函数的参数,而实例化ThreadStart时所用到的方法是没有参数的。

为什么是Object这样的参数呢?很简单,因为在.net中Object是所有类型的基类,用它可以表示Array(数组)、Interface(接口)、ValueType(值类型,如bool,byte,char,short,int,float,long,double等)、class(类)等.net中的类型。当然,这也意味着如果你要启动一个线程,给它传递一个int类型参数时,必须在启动方法中进行相应的类型转换。

下面就是一个例子,在启动线程时指定了线程的暂停间隔,代码如下:

namespace StartThread
{

 class Program

    {

        int interval = 200;

        static void Main(string[] args)

        {

            Program p = new Program();

            //带参数的启动方法

         Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));

            parameterThread.Name = "Thread A:";

            parameterThread.Start(30);        

        }

        /// <summary>  

        /// 带参数的启动方法  

        /// </summary>  

        /// <param name="ms">让线程在运行过程中的休眠间隔</param>  

        public void ParameterRun(object ms)

        {

            int j = 10;

    //这里采用了TryParse方法,避免不能转换时出现异常  

            int.TryParse(ms.ToString(), out j);           

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

            {

                Console.WriteLine(Thread.CurrentThread.Name + "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());

                Thread.Sleep(j);//让线程暂停  

            }

            Console.Read();       

}

}

}

在这个方法里,我们在启动线程时顺便指定了线程的暂停间隔,也就是这句:

 parameterThread.Start(30);

线程启动时运行的方法是public void ParameterRun(object ms),这个值为30的int类型变量被装箱成object,所以在方法中还需要将它转换成int类型,这个可以通过拆箱或者其它办法解决。

假如我们要启动两个线程,每个线程的暂停间隔不一样,启动代码如下:

namespace StartThread

{

class Program

    {

        int interval = 200;

        static void Main(string[] args)

        {

            Program p = new Program();

            //带参数的启动方法

          Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));

            parameterThread.Name = "Thread A:";

            parameterThread.Start(30);

       parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));

            parameterThread.Name = "Thread B:";

            parameterThread.Start(60);             

        }

        /// <summary>  

        /// 带参数的启动方法  

        /// </summary>  

        /// <param name="ms">让线程在运行过程中的休眠间隔</param>  

        public void ParameterRun(object ms)

        {

            int j = 10;

    //这里采用了TryParse方法,避免不能转换时出现异常  

            int.TryParse(ms.ToString(), out j);           

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

            {

                Console.WriteLine(Thread.CurrentThread.Name + "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());

                Thread.Sleep(j);//让线程暂停  

            }

            Console.Read();       

}

}

}

对上面的代码做一点说明,就是线程启动之后,线程的实例不必再存在,例如在上面的代码中我用的是同一个实例实例化了两个线程,并且这两个线程运行很正常。

3、以类的实例作为参数

上面解决了一个问题,如果在启动线程时需要参数如何解决,如果针对上面的问题继续发掘,比如:在启动线程时不但要指定线程的暂停间隔,还需要指定循环次数(在上面的所有例子中都是执行10次的),这个问题该如何解决呢?

有两种办法可以解决:

首先可以继续在ParameterizedThreadStart这里做文章,因为这里可以使用一个Object类型的参数,那么可以通过数组或者一个类来解决(因为它们都是Object的子类)。我在做某个系统时确实采用数组处理过这种情况,这样就要求在线程启动方法中必须清楚知道数组中每个参数的用途,不是太方便。 这里说说重新定义一个实体类来解决的方法,代码如下。

namespace StartThread

{

    class MyThreadParameter

    {

        private int interval;

        private int loopCount;

        /// <summary>  

        /// 循环次数  

        /// </summary>  

        public int LoopCount

        {

            get { return loopCount; }

        }

        /// <summary>  

        /// 线程的暂停间隔  

        /// </summary>  

        public int Interval
        {
            get { return interval; }
        }

        /// <summary>  

        /// 构造函数  

        /// </summary>  

        /// <param name="interval">线程的暂停间隔</param>  

        /// <param name="loopCount">循环次数</param>  

        public MyThreadParameter(int interval, int loopCount)

        {

            this.interval = interval;

            this.loopCount = loopCount;

        }     

    }

   class Program

    {

        int interval = 200;

        static void Main(string[] args)

        {

            Program p = new Program();

         Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));

            parameterThread.Name = "Thread A:";

            MyThreadParameter paramter = new MyThreadParameter(50, 20);

            parameterThread.Start(paramter);            

        }

        /// <summary>  

        /// 带参数的启动方法  

        /// </summary>  

        /// <param name="ms">让线程在运行过程中的休眠间隔</param>  

        public void ParameterRun(object ms)

        {

            MyThreadParameter parameter = ms as MyThreadParameter;//类型转换  

            if (parameter != null)

            {

                for (int i = 0; i < parameter.LoopCount; i++)

                {

            Console.WriteLine(Thread.CurrentThread.Name + "系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());

                     Thread.Sleep(parameter.Interval);//让线程暂停  

                }

                Console.Read();

            }     

}

}

}

第二种方法和上面方法有些相似,也是需要引入外部类,并且将Thread实例放在引入的类中,这种情况适合于在线程中处理的业务逻辑比较复杂的情况。

4、把Thread要处理的业务代码放在一个单独的类中

在前不久处理的一个项目中我用过这种情况,它是用来实现双向数据传输的。

如果实现上面的效果,代码如下:

namespace StartThread

{

    class MyThreadParameter

    {

        private int interval;

        private int loopCount;

        private Thread thread;

        /// <summary>  

        /// 循环次数  

        /// </summary>  

        public int LoopCount

        {

            get { return loopCount; }

        }

        /// <summary>  

        /// 线程的暂停间隔  

        /// </summary>  

        public int Interval

        {

            get { return interval; }

        }

        /// <summary>  

        /// 构造函数  

        /// </summary>  

        /// <param name="interval">线程的暂停间隔</param>  

        /// <param name="loopCount">循环次数</param>  

        public MyThreadParameter(int interval, int loopCount)

        {

            this.interval = interval;

            this.loopCount = loopCount;

            thread = new Thread(new ThreadStart(Run));

        }

        public void Start()

        {

            if (thread != null)

            {

                thread.Start();

            }

        }

        private void Run()

        {

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

            {

                Console.WriteLine("系统当前时间毫秒值:" + DateTime.Now.Millisecond.ToString());

                Thread.Sleep(interval);//让线程暂停  

            }

        }  

}

class Program

    {

        static void Main(string[] args)

        {

            MyThreadParameter parameterThread = new MyThreadParameter(30, 50);

            parameterThread.Start();          

        }       

}

}

上面的代码的运行效果和前面的代码运行效果类似,只不过是将业务处理代码放在一个单独的类MyThreadParameter中,使得MyThreadParameter看起来也像一个Thread,实际上维护的还是其内部的Thread,在一些大型系统中这样做的好处是便于维护。

总结:在本篇主要讲述如何启动线程的问题,在启动时可能会遇到无需参数、需要多个参数的情况,在这里讲述了如何解决这些问题的思路。在.net类库中虽然存在着庞大的类库,但是并不是总会有合适的类来解决我们所遇到的问题,但是只要肯动脑筋总会想到合适的办法。

时间: 2024-10-11 06:21:23

线程的启动(转)的相关文章

为何只能在其关联的线程内启动timer?(Qt会检查一致性,否则就不执行)

为何只能在其关联的线程内启动timer? 在QTimer源码分析(以Windows下实现为例) 一文中,我们谈到: QTimer的是通过QObject的timerEvent()实现的,开启和关闭定时器是通过QObject的startTimer()和killTimer完成的. startTimer最终调用对象关联线程的eventDispatcher来注册定时器: int QObject::startTimer(int interval) { Q_D(QObject); return d->thre

015 线程退出 启动

线程退出 启动  ● 当一个进程销毁的时候 ○ 销毁临时对象 ○ 释放堆栈 ○ 将返回值设置为我的退出代码 ○ 减少进程内核对象的使用次数 ● 当一个线程销毁的时候 ○ 销毁临时对象 调用我的们的析构函数 ○ 释放当前线程里面锁分配堆栈 -> 窗口 -> HOOK ○ 将返回值设置为我的退出代码 线程的入口函数的返回值设置为我的退出代码 ○ 减少进程内核对象的使用次数 ● ExitThread 立即结束当前线程 ● TerminateThread 可以结束其他的线程 ● Exit ○ 会将属于

1、线程的启动

我们要启动一个线程,就是调用一个线程实例的start方法.让我们来看看start方法的源码: 1 public synchronized void start() { 2 3 //0值就表示这个线程是新启动的 4 if(threadStatus!=0) { 5 throw new IllegalThreadStateException(); 6 } 7 8 //通知线程群,这个线程已经启动,线程群的"没有启动的数量"属性将减一. 9 group.add(this); 10 11 boo

C#多线程 线程的启动

在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动时要运行的方法.在.net中提供了两种启动线程的方式,一种是不带参数的启动方式,另一种是带参数的启动的方式. 不带参数的启动方式 如果启动参数时无需其它额外的信息,可以使用ThreadStart来实例化Thread,如下面的代码: 1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.T

Python的并发并行[4] -&gt; 并发 -&gt; 利用线程池启动线程

利用线程池启动线程 submit与map启动线程 利用两种方式分别启动线程,同时利用with上下文管理来对线程池进行控制 1 from concurrent.futures import ThreadPoolExecutor as tpe 2 from concurrent.futures import ProcessPoolExecutor as ppe 3 from time import ctime, sleep 4 from random import randint 5 6 def f

线程的启动和停止

import java.lang.Thread;import java.lang.Runnable;import java.util.Date; public class DefineAndStartThread{ class ThreadA extends Thread{ private Date runDate; //继承Thread的子类必须实现run方法,Thread中的run方法未做任何事 public void run(){ System.out.println("ThreadA b

多线程基础二(线程的启动、终止,线程面临的三种问题)

一.线程的启动.终止方式 启动: start native(调用外部接口启动) 终止:    stop(类似kill,暴力终止)  interrupt 中断的方式 通过指令的方式 volatile boolean stop = false; public class InterruptDemo { private static int i; public static void main(String[] args) { Thread thread = new Thread(()->{ whil

PoEdu - Windows阶段班 【Po学校】Lesson006_线程_线程的启动到消亡 &amp;线程状态 &amp; 线程安全 &amp; CONTEXT结构体 &amp; 令牌锁

011_线程启动到死亡的详细讲解 1. 线程内核对象 使用计数 2 ##决定当前线程何时销毁 暂停计数 1 ##UINT类型初始为1,可以暂停多次,如置为0则取消暂停. 退出代码 STILL_ACTIVE Signaled FALSE CONTEXT 为空 2. 栈##在隶属于当前进程的空间中,分配一块"栈"空间,以供线程使用 参数 lpParam 入口地址 lpfnAddr 3. CONTEXT##线程上一次运行时的寄存器 IP(指令寄存器) void RtlUserThreadSt

RunLoop在main线程和自己创建的线程如何启动

本文介绍:这篇博客主要是描述的是RunLoop的启动机制.内容属于简单的系类的. 一.RunLoop和线程的关系 每一个RunLoop对应一个线程.每一个线程都可以拥有一个RunLoop,这也就是说线程可以创建一个属于自己的Runloop,也可以不创建自己的RunLoop.这都是根据程序内部的需求来决定的.这里需要注意的是:你创建一个runLoop但是你还必须要手动的让其run. 二.main线程的RunLoop 主线程是灌注这个程序的.而与main线程相对应的RunLoop是在程序启动的时候就