C#多线程实践——线程同步

下面的表格列展了.NET对协调或同步线程动作的可用的工具:

                      简易阻止方法


构成


目的


Sleep


阻止给定的时间周期


Join


等待另一个线程完成

                      锁系统


构成


目的


跨进程?


速度


lock


确保只有一个线程访问某个资源或某段代码。




Mutex


确保只有一个线程访问某个资源或某段代码。可被用于防止一个程序的多个实例同时运行。



中等


Semaphore


确保不超过指定数目的线程访问某个资源或某段代码。



中等

                    信号系统


构成


目的


跨进程?


速度


EventWaitHandle


允许线程等待直到它受到了另一个线程发出信号。



中等


Wait 和 Pulse*


允许一个线程等待直到自定义阻止条件得到满足。



中等

同步要领

阻止(Blocking)

  当一个线程通过上面所列的方式处于等待或暂停的状态,被称为被阻止。一旦被阻止,线程立刻放弃它被分配的CPU时间,将它的ThreadState属性添加为WaitSleepJoin状态,直到停止阻止。停止阻止由以下任一条件触发:

  • 阻止的条件已得到满足
  • 操作超时(如果timeout被指定了)
  • 通过Thread.Interrupt中断了
  • 通过Thread.Abort放弃了

当线程通过(不建议)Suspend 方法暂停,不认为是被阻止了。

休眠 和 轮询

  调用Thread.Sleep阻止当前的线程指定的时间(或者直到中断):

static void Main() {
    Thread.Sleep (0);                           // 释放CPU时间片
    Thread.Sleep (1000);                        // 休眠1000毫秒
    Thread.Sleep (TimeSpan.FromHours (1));      // 休眠1小时
    Thread.Sleep (Timeout.Infinite);            // 休眠直到中断
}

  确切地说,Thread.Sleep放弃了占用CPU,请求不再被分配时间直到超过某个给定的时间。Thread.Sleep(0)放弃CPU的时间刚刚够其它在时间片队列里的活动线程(如果有的话)被执行。

Thread.Sleep在阻止方法中是唯一的暂停捕获Windows Forms程序的Windows消息的方法,在Windows Forms程序中是一个很大的问题,任何对主UI线程的阻止都将使程序失去相应。因此一般避免这样使用,无论信息获取是否被“技术地”暂定与否。线程类同时也提供了一个SpinWait方法,它使用轮询CPU而非放弃CPU时间的方式,保持给定的迭代次数进行“无用地繁忙”。50迭代停顿大约一微秒,一般取决于CPU的速度和负载。从技术上讲,SpinWait并不是一个阻止的方法:一个处于spin-waiting的线程的ThreadState不是WaitSleepJoin状态,并且也不会被其它的线程过早的中断(Interrupt)。SpinWait很少被使用,它的作用是等待一个在极短时间(可能小于一微秒)内可准备好的可预期的资源,而不用调用Sleep方法阻止线程而浪费CPU时间。不过,这种技术的优势只有在多处理器计算机:对单一处理器的电脑,直到轮询的线程结束了它的时间片之前,一个资源没有机会改变状态,这有违它的初衷。并且调用SpinWait经常会花费较长的时间这本身就浪费了CPU时间。

 阻止 vs. 轮询

线程可以等待某个确定的条件来明确轮询使用一个轮询的方式,比如:

while (!proceed);

或者:

while (DateTime.Now < nextStartTime);

  这是非常浪费CPU时间的:对于CLR和操作系统而言,线程进行了一个重要的计算,所以分配了相应的资源!在这种状态

下的轮询线程不算是阻止,不像一个线程等待一个EventWaitHandle(一般使用这样的信号任务来构建)。

阻止和轮询组合使用可以产生一些变换:

while (!proceed) Thread.Sleep (x); // "轮询休眠!"

 x越大,CPU效率越高,折中方案是增大潜伏时间,任何20ms的花费是微不足道的,除非循环中的条件是极其复杂的。

除了稍有延迟,这种轮询和休眠的方式可以结合的非常好,可能它最大的用处在于程序员可以放弃使用复杂的信号结构来工作了。

使用Join等待一个线程完成

可以通过Join方法阻止线程直到另一个线程结束:

class ThreadDemo {

    static void Main() {

    Thread t = new Thread (delegate() { Console.ReadLine();});

    t.Start();

    t.Join(); // 等待直到线程完成

    Console.WriteLine ("Thread t‘s ReadLine complete!");

    }

}

  Join方法也接收一个使用毫秒或用TimeSpan类的超时参数,当Join超时是返回false,如果线程已终止,则返回true 。

  Join所带的超时参数非常像Sleep方法,实际上下面两行代码几乎差不多:

Thread.Sleep (1000);
Thread.CurrentThread.Join (1000);

  他们的区别明显在于单线程的应用程序域与COM互操作性:在阻止时,Join保持信息捕获,Sleep暂停信息捕获。

时间: 2024-08-02 10:50:13

C#多线程实践——线程同步的相关文章

mfc小工具开发之定时闹钟之---多线程急线程同步

一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等.用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等.但对于Win32的API编程而言,这两种线程是没有区别的,它们都只需线程的启动地址即可启动线程来执行任务. 在MFC中,一般用全局函数Afx

MFC——9.多线程与线程同步

Lesson9:多线程与线程同步 程序.进程和线程是操作系统的重点,在计算机编程中,多线程技术是提高程序性能的重要手段.本文主要讲解操作系统中程序.进程和线程之间的关系,并通过互斥对象和事件对象实例说明多线程和线程同步技术. 1.      程序.进程和线程 1.1  程序和进程 程序是计算机指令的集合,它以文件的形式存储在磁盘上.进程通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动.进程是资源申请.调度和独立运行的单位,因此,它使用系统中的运行资源:而程序不能

java多线程之 ---- 线程同步

java多线程之线程同步 线程同步 定义:同步是指在同一时间段内只能运行一个线程. 分类:同步方法.同步块. 作用:安全解决共享问题. 同步块: 语法: synchronized (同步对象) { 需要同步的代码; } 例子: public class ThreadDemo implements Runnable{ private int ticket = 5; public void run(){ for(int i=1;i<=5;i++){ synchronized (this){ if(t

Linux程序设计学习笔记----多线程编程线程同步机制之互斥量(锁)与读写锁

互斥锁通信机制 基本原理 互斥锁以排他方式防止共享数据被并发访问,互斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个互斥锁逻辑上绑定之后,对该资源的访问操作如下: (1)在访问该资源之前需要首先申请互斥锁,如果锁处于开状态,则申请得到锁并立即上锁(关),防止其他进程访问资源,如果锁处于关,则默认阻塞等待. (2)只有锁定该互斥锁的进程才能释放该互斥锁. 互斥量类型声明为pthread_mutex_t数据类型,在<bits/pthreadtypes.h>中有具体的定义. 互斥量

C#多线程之线程同步3

在上一篇C#多线程之线程同步2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier构造.ReaderWriterLockSlim构造和SpinWait构造. 七.使用Barrier构造 在这一小节中,我们将学习一个比较有意思的同步构造:Barrier.Barrier构造可以帮助我们控制多个等待线程达到指定数量后,才发送通知信号,然后所有等待线程才能继续执行,并且在每次等待线程达到指

关于Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文)

Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文) 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享给大家. 一.对于线程同步和同步锁的理解(注:分享了三篇高质量的博客) 以下我精心的挑选了几篇博文,分别是关于对线程同步的理解和如何选择线程锁以及了解线程锁的作用范围. <一>线程同步锁的选择 1. 这里我推荐下Java代码质量改进之:同步对象的选择这篇博文. 2. 以上推荐的博文是以卖火车票为例

系统API函数实现多线程及线程同步

1.线程的创建 须包含头文件:#include <windows.h> HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); lpThreadAttributes:指向SECURI

C# 多线程(二) 线程同步基础

本系列的第一篇简单介绍了线程的概念以及对线程的一些简单的操作,从这一篇开始讲解线程同步,线程同步是多线程技术的难点.线程同步基础由以下几个部分内容组成 1.同步要领(Synchronization Essentials) 2.锁(Locking) 3.线程安全(Thread Safety) 4.事件等待句柄(Signaling with Event Wait Handles) 5.同步上下文(Synchronization Contexts) 同步要领(Synchronization Essen

多线程之线程同步

多线程内容大致分两部分,其一是异步操作,可通过专用,线程池,Task,Parallel,PLINQ等,而这里又涉及工作线程与IO线程:其二是线程同步问题,鄙人现在学习与探究的是线程同步问题. 通过学习<CLR via C#>里面的内容,对线程同步形成了脉络较清晰的体系结构,在多线程中实现线程同步的是线程同步构造,这个构造分两大类,一个是基元构造,一个是混合构造.所谓基元则是在代码中使用最简单的构造.基元构造又分成两类,一个是用户模式,另一个是内核模式.而混合构造则是在内部会使用基元构造的用户模