您的位置:首页 > 编程语言 > C#

C#多线程基础

2014-01-15 15:12 309 查看
线程基础

一个进程由若干个线程组成,线程是程序执行的基本原子单位。线程是"进程"中某个单一顺序的控制流,线程是进程中的一个基本执行流,每个线程都有自己专属的寄存器(程序计数器、栈指针等),代码共享区,不同的线程可以执行同样的方法。

多线程可以实现并行处理,可以避免某项任务长时间占用CPU时间,需要注意的是,多线程程序对于效率,应该根据任务不同的要求来选择。

线程的命名空间System.Threading

Thread类是线程中最重要的一个,Thread类提供了创建并控制线程,设置其优先级并获取其状态的方法。

Thread类的声明:

class ThreadSimple

{

//静态线程函数

public static void ThreadMethodExample()

{

}

}

//调用静态方法

Thread threadSimple = new Thread(ThreadSimple.ThreadMethodExample);

或:

class ThreadSimple

{

//静态线程函数

public static void ThreadMethodExample()

{

}

//调用静态方法

//Thread threadSimple = new Thread(ThreadSimple.ThreadMethodExample);

Thread threadSimple = new Thread(new ThreadStart(ThreadMethodExample));

}

线程启动、结束
Thread类的常用方法:

IsAlive:判断线程是否处于活动状态

Name:线程的名称

Priority:ThreadPriority枚举类型,代表线程的优先级{Normal,AboveNormal,BelowNormal,Highest,Lowest}

ThreadState:ThreadState枚举类型,代表线程的状态 { Running(线程已启动,正在执行) , StopRequested(正在请求停止此线程), SuspendRequested(正在请求挂起此线程), Background(线程正在被作为后台线程执行), Unstarted(尚未启动线程),Stopped(线程已经停止),WaitSleepJoin(线程已经被阻止),Suspended(线程已经挂起),AbortRequested(对线程调用了Thread.Abort()方法但是线程尚未收到试图终止它的挂起的System.Threading.ThreadAbortException) , Aborted(线程状态包括AbortRequested,并且该线程现在已死,但其状态尚未更改为Stopped) }

Start:启动一个线程

Suspend:挂起一个线程的运行(暂停、中断)

Resume:继续被挂起的线程,恢复被Suspend()方法挂起的线程的执行

Abort():结束一个线程的运行,终止线程

Sleep():线程的休眠,使线程进入一定时间的休眠状态,时间一到,线程继续执行

线程间数据同步

线程间数据共享
多线程编程中,如果线程间需要共享数据,需要把共享的数据设置为静态类型的,此时可以使用static关键字

Lock语句同步数据访问
线程之间的同步和通信处理,两个线程需要同时操作一个队列,一个线程进行添加操作,另一个线程进行取用元素操作。

lock关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。Lock的语法:lock(expression)statement_block【其中expression是加锁对象,必须是引用类型,不能是数值类型,statement_block代表正在访问的共享资源的程序段】,

lock语句可以很好地实现互斥操作,从而保护数据在某个时刻内只有一个线程可以操作该数据,直至操作完成才允许其他线程进行操作,这样就实现了按顺序操作的设计,从而避免不可预料的情况发生。

public static void MethodSubB()

{

do

{

lock(lockExample)

{

i-=1;

Console.WriteLine("线程2开始,共享数据为:i={0}",i);

Thread.Sleep(2000); //线程A休眠2秒

Console.WriteLine("线程2结束,共享数据值i={0}",i);

}

} while (true);

}

    3.Mutex类同步数据访问
    只向某个线程授予对共享资源的独占访问权,如果一个获取了互斥体,那么想要获取该互斥体的其他线程将被挂起,直到这个线程释放该互                 斥体。
    线程可以使用Mutex.WaitOne()方法释放这个对象,而在此期间,其他想要获取这个Mutex对象的线程都只能等待。

    4.Monitor类同步数据访问数
Monitor类用于锁定对象,一个线程只有得到这把锁才能对该对象进行操作,对象锁保证了在可能引起混乱的情况下,一个时刻只有一个线程可以访问这个对象。

Monitor必须和一个具体的对象相关联,但由于它是一个静态类,所以不能使用它来定义对象,而且它的所有方法都是静态的,不能使用对象来引用。

当一个线程调用Monitor.Enter()方法锁定对象时,这个对象就归它所有了,其他线程想要访问这个对象,只有等待它调用Monitor.Exit()方法释放锁。

Monitor类主要成员

Enter

在指定对象上获取排他锁

Exit

释放指定对象上的排它锁

Pluse

通知等待队列中的线程锁定对象状态的更改

PluseAll

通知所有的等待线程对象状态的更改

TryEnter

试图获取指定对象上的排他锁

Wait

释放对象上的锁并阻止当前线程,直到它重新获取该锁

private static Object sObjectA = new Object();

private static Object sObjectB = new Object();

public static void DemoA()

{

if(Monitor.TryEnter(sObjectA,1000))

{

Thread.Sleep(1000);

if (Monitor.TryEnter(sObjectB, 2000))

{

Monitor.Exit(sObjectB);

}

else

{

Console.WriteLine("TryEnter SObjectB超时...");

}

Monitor.Exit(sObjectA);

}

Console.WriteLine("执行DemoA");

}

public static void DemoB()

{

if (Monitor.TryEnter(sObjectB, 1000))

{

Thread.Sleep(1000);

if (Monitor.TryEnter(sObjectA, 2000))

{

Monitor.Exit(sObjectA);

}

else

{

Console.WriteLine("TryEnter SObjectA超时...");

}

Monitor.Exit(sObjectB);

}

Console.WriteLine("执行DemoB");

}

static void Main(string[] args)

{

Thread threadA = new Thread(DemoA);

Thread threadB = new Thread(DemoB);

threadA.Start();

threadB.Start();

Thread.Sleep(4000);

Console.WriteLine("线程结束");

}

    5.带参数线程

    在不传递参数的情况下,可以使用ThreadStart代理来执行函数,如果要传递参数给执行函数,则可使用ParameterizedThreadStart代理来链接函数

    Thread类的4个重载的构造函数

      1.Thread(ThreadStart)[初始化Thread类的新实例]

      2.Thread(ParameterizedThreadStart)

      [初始化Thread类的新实例,指定允许对象在线程启动时传递给线程的委托]

      3.Thread(ParameterizedThreadStart,Int32)

      4.Thread(ThreadStart,Int32)

      [初始化Thread类的新实例,并指定线程的最大堆栈]

实例:

class ThreadDemo

{

public int paraA, paraB;

public void MethodDemo()

{

Console.WriteLine("paraA={0},paraB={1}", paraA, paraB);

}

public void Print(object obj)

{

Console.WriteLine("传入的参数是{0}", obj.ToString());

}

}

static void Main(string[] args)

{

ThreadDemo A = new ThreadDemo();

A.paraA = 2;

A.paraB = 3;

Thread threadA = new Thread(new ThreadStart(A.MethodDemo));

threadA.Start();

Thread threadB = new Thread(new ParameterizedThreadStart(new ThreadDemo().Print));

threadB.Start(" 这是传入的参数");

Console.Write("Press any key to continue...");

Console.ReadKey();

}

  6.线程池ThreadPool

线程池是可以在后台执行多个任务的线程集合,这使得主线程可以自由地异步执行其他任务。一旦池中的某个线程任务完成,它将返回到等待线程队列中等待在此被使用。线程池线程都是后台线程。

以下情况应该使用单独的线程不宜使用线程池

1.线程需要指定优先级

2.线程执行的时间较长

3.线程在单独的线程apartment中

4.在线程执行的过程中对线程存在操作

static void MethodA(object num)

{

int QueueNum = (int)num;

Console.WriteLine("线程号:{0}", QueueNum);

//输出空行,为了美观

Console.WriteLine();

}

static void Main(string[] args)

{

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

{

//在线程池中创建线程池线程来执行指定的方法(用WaitCallBack来表示),并将此线程排入线程池的队列等待执行

ThreadPool.QueueUserWorkItem(new WaitCallback(MethodA), i);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: