精华内容
下载资源
问答
  • 该项目包含用于实现FT2232H(FT245同步和异步模式用于高速USB传输的同步FIFO的文件。 要求: ipython2 ipython notebook cocotb iverilog gource gtkwave 用法: To open ipython notebook, run: ./run.sh...
  • 同步异步模式

    千次阅读 2014-07-03 10:16:36
    这篇文字介绍了半同步异步模式,这个模式运用在复杂的并行系统中,把同步和异步I/O模型集成在一起,既保持了编程简单又保证了执行的效率。这个模式中,高层使用同步I/O模型,简化编程。低层使用异步I/

    半同步半异步模式
    一个架构模式,清晰的结构,高效并发的I/O

    译者:

    英文原文: http://www.cs.wustl.edu/~schmidt/PDF/HS-HA.pdf

    摘要
    这篇文字介绍了半同步半异步模式,这个模式运用在复杂的并行系统中,把同步和异步I/O模型集成在一起,既保持了编程简单又保证了执行的效率。这个模式中,高层使用同步I/O模型,简化编程。低层使用异步I/O模型,高效执行。各种操作系统和其它复杂的并行系统中广泛使用这个模式,使用这个模式的操作系统有:UNIX, Mach,Windows NT,and VMS。

    1 意图
    在系统中分离了同步I/O和异步I/O的两个过程,既简化了并行程序实现的复杂,又不会影响执行的效率。

    2 动机
    如图一所示,为了说明半同步半异步模式,我们来考虑一个软件架构,BSD UNIX[1]的网络子系统。BSD UNIX的内核负责协调异步通信设备(如:网络适配器、远程终端)和应用程序之间的I/O行为。数据包随时到达设备,产生硬件中断,然后由中断处理例程把数据交给操作系统内核。这些中断处理例程接收数据,触发上层的网络协议处理(如 IP,TCP和UDP)。应用数据包在套接口层排队。操作系统把这些数据包分发给每个用户进程。用户进程使用系统调用read,以同步的方式接收套接口层的数据。用户进程可以在任意时刻调用read,当数据没有到达的时候,进程将一直阻塞等待。

    在这个体系中,操作系统内核响应设备的中断,执行异步的I/O。而用户级的应用程序进行同步的I/O。这正是“半同步半异步”这个名字的由来,这个结构满足下面的两个需要:

    编程实现简单。异步I/O模型中,中断随时触发输入和输出操作,编程复杂。使用异步I/O模型,当中断处理例程拥有线程控制权时,会产生非常麻烦的时序和竟争问题。而且,使用中断机制的程序要求额外的数据结构,这个数据结构用于在异步事件发生的时候保存进程上下文状态。并且,程序执行的时候,外部的事件会在不固定的时间发生,程序不容易调试。

    与其相比,使用同步I/O模型的时候,I/O操作在确定的点发生,编程实现要容易的多。此外,同步I/O操作的程序会阻塞等待I/O操作的完成。进程运行上下文的活动记录自动在运行栈中保存,不必使用独立的数据结构。因此,为了让编程简单,有强烈的理由使用同步I/O模型。

    程序执行高效。在中断驱动的设备上,异步I/O模型运用带来了高效率。异步I/O让通信和计算同时进行。并且,因为程序运行状态的数据量相对较小,上下文切换的消耗被最小化[2]。因此,为了提高运行的性能,也有强烈理由使用异步I/O模型。

    与其相比,如果每种资源的事件(例如网卡,终端和计时器)占用一个独立的活动对象(进程或线程),一个完全同步I/O模型效率会低。每个活动对象包含多个资源(例如栈,寄存器),每种资源都会让它阻塞,等待资源事件的发生。在创建,调度,分发和终止这些独立的活动对象,会消耗更多的时间和空间。

    3 方案
        编程简单和高效率执行是矛盾的,半同步半异步模式目的正是为了解决这个矛盾。这个模式集成了同步和异步两种I/O模式,结构清晰,效率高。在这个模式中,上层的任务(如:数据库查询,文件传输)使用同步I/O模型,简化了编写并行程序的难度。而底层的任务(如网络控制器的中断处理)使用异步I/O模型,提供了执行效率。一般情况下,上层的任务要比下层的任务多,使用一个简单的层次实现异步处理的复杂性,可以对外隐藏异步处理的细节。另外,同步层次和异步层次任务间的通信使用一个队列来协调。   

    4 应用 
    半同步半异步模式在下面的场景中使用。

    × 一个系统中的进程有下面的特征:
    系统必须响应和处理外部异步发生的事件,
    如果为每一个外部资源的事件分派一个独立的线程同步处理I/O,效率很低。
    如果上层的任务以同步方式处理I/O,实现起来简单。

    × 一个或多个任务必须在单独的控制线程中执行,其它任务可以在多线程中执行。
    例如,X Window和Sun RPC 的库函数许多是不可重入的。多个控制线程不能安全地同时调用这些函数。然而,为了使多个CPU提高服务的质量,有必要使用并行,不同的线程同时执行批量数据的传输或数据库的查询。使用半同步半异步模式,可以在多线程中分离出单独的线程。在不改变现有代码的情况下,这个分离可以让不可重入的函数在并行环境正确执行。

    5 结构和组成单元
    图二显示了半同步半异步模式的组成结构。这些组成单元如下描述

    ×同步任务层(用户级的进程)
    本层的任务完成上层的I/O操作,使用同步I/O模型,通过队列层的队列中传输数据。和异步层不同,同步层的任务使用活动对象[3]执行,这些活动对象有自己运行栈和寄存器状态。当执行同步I/O的时候,他们会被阻塞/睡眠。

    ×队列层(套接口层)
    这个层在同步任务层和异步任务层之间,提供了同步控制和缓存的功能。异步任务的I/O事件被缓存到消息队列中,同步任务层在队列中提取这些事件(相反方向亦然)。

    ×异步任务层
    处理低层的事件,这些事件由多个外部的事件源产生(例如网卡,终端)。和异步任务不同,此层的实体是被动对象,没有自己的运行栈,要求不能被阻塞。

    ×外部事件源(网络接口)
    外部设备产生事件,产生的事件先被异步任务层接收和处理。

    6 协作
    图三展现了一个动态的过程:当外部事件到达后,半同步半异步模式的各个组成单元协作和处理。把协作的过程分成下面三个阶段:

    ×异步阶段。通过中断机制或异步事件通知,外部的事件源和异步任务层完成交互。

    ×排队阶段。队列层的队列提供了一个同步控制机制,响应输入事件,缓存同步层和异步层之间的消息,

    ×同步阶段。同步任务层在队列层提取消息。注意,同步层和异步层专递数据的协议是独立的,和队列层具体处理通信的方式无关。
    在图三中,同步层和异步层之间的通信使用生产者/消费者模型。理解这个模型的关键是:完成同步任务的是活动对象。他们可以在任意时刻阻塞调用read或在 write。如果数据没有准备好,这些活动对象可以一直等待。相反的,异步任务层的实体是被动对象。他们不能被阻塞。这些对象被通知或外部对象触发。

    7 结果
    半同步半异步模式有下面的优点

    ×上层的任务被简化,这是因为不需要再面对底层的异步I/O。复杂的并发控制,中断处理和计时操作都委托给异步任务层。异步层负责处理底层的细节,如,异步系统编程的中断处理。异步任务层管理与硬件相关的组件间(如DMA,内存管理,设备寄存器)的交互。

    ×不同层可以使用不同的同步策略。每一层不必使用相同的并行控制方式。例如,在单线程的BSD UNIX内核中,异步任务层使用低级的机构(如修改CPU的中断级别)。与此不同,用户级的进程使用高级的同步机构(如使用信号量,消息队列,条件变量,记录锁)。

    ×层间的通信被限制在单独的一点,因为所有的交互使用队列层协调。队列层对两层之间的消息进行缓存。如果直接通信,同步和异步任务层直接访问对方的内存,就必须使用复杂的锁和时序控制。

    ×在多处理器环境中提高了性能。使用同步的I/O可以简化编程和提高性能。例如,长时间的数据传输(如从数据库中加载一个大的医学图象)使用同步I/O效率更高。因为一个处理器单独为一个线程使用,可以更有效的使用CPU的指令和数据的缓存。

    半同步半异步模式有下面的缺点

    × 跨边界导致的性能消耗,这是因为同步控制,数据拷贝和上下文切换会过度地消耗资源。在同步和异步任务层之间使用队列层传送数据的时候,这种消耗往往会发生。特别是,许多使用半同步半异步模式的操作系统,把队列层放到用户和内核域的边界上。到跨越这个边界的时候,往往会有明显的性能消耗。例如,BSD UNIX的套接口层,在很大比例上造成了TCP/IP网络的过载[4]。

    ×上层任务缺少异步I/O的实现。依赖与系统接口的设计,可能导致上层无法直觉使用低层的异步I/O设备。因此,如果外部的设备支持异步的重叠的I/O方式,系统的I/O结构会防碍应用程序高效的使用。

    8 实现
    这一节描述如何实现半同步半异步模式,系统中分成了同步任务层和异步任务层,两层之间使用队列层通信。
       
    8.1 找到消耗时间的长时任务,使用同步I/O实现他们。
    使用同步I/O方式,可以让系统任务的实现简单化,而系统中经常有会时间长的任务,如执行大量流数据碰[5]传输,或者是等待服务器响应的数据查询。

    使用活动对象[3]模型实现这些长时任务。活动对象拥有自己的运行栈和寄存器状态,在执行同步I/O的时候可以被阻塞。实现活动对象结构,要求一个控制线程的切换机制,需要一个地方存放和恢复线程的状态(如寄存器的值,栈指针),这些功能足够实现一个非抢占的,没有内存保护的线程机构。“用户级线程”包一般实现了此类的功能(译者:操作系统都实现了这个功能)。
    然而,在一个要求健壮的多任务系统中,要使用进程或线程的方式实现活动对象,需要更多的功能。这种情况下,每种线程需要自己的线程(或进程)空间,这些空间被处理器的内存管理单元(MMU)管理。当线程(或进程)切换的时候,新的地址空间信息需要加载到MMU中。切换时还需要清空高速缓存,特别是高速缓存使用虚拟地址的情况下。除了地址空间,一个操作系统进程还可能包含一个“用户ID”。这个标识告诉操作系统这个进程的访问权限和占用的系统资源。
    为了防止一个单独的线程(或进程)永久的占用系统,要有抢占的机制。经常使用计时器实现,计时器周期性的产生时钟中断。在中断处理期间,操作系统检查当前的进程是否应该被抢占。如果应该被抢占,就保存当前进程的状态,加载下一个进程的状态运行。
          
    8.2 找到短时任务,使用异步I/O实现
    系统中的一些任务不能阻塞过长的时间。这些任务一般和外界事件完成一个短期的交互过程(如图形用户界面或中断驱动的网络接口器),为了提高效率和保证响应速度,这些外部事件的处理一定不能阻塞。
    实现这样的短期任务,要使用被动对象[6]模型。被动对象使用别人的控制线程(调用者的线程或者一个独立的中断栈)。因为他们不能常时间的等待,不能被阻塞。不阻塞的主要目标是保证其响应时间(如高优先级的硬件中断,如时钟中断)。
    实现一个结构清晰的异步I/O框架,有多种方式。

    × 使用反应堆模式[6]实现多路事件的处理,反应堆模式使用一个单线程的处理循环,把多路的事件派发给多个处理者。这个模式组合了单线程处理循环的简单性和面向对象编程提供的可扩展性。反应堆模式在一个线程(或进程)中进行顺序的消息处理,常用来消除多线程同步和加锁处理的复杂性。
    一个反应堆可以使用在同步或者异步的事件源上。但是它支持的事件处理者的行为要求是异步的。也就是说,为了不影响其它事件源的响应效率,事件处理者是不能阻塞的。

    ×实现一个多级的中断处理机构。这种机构下,当更高级别的任务(如硬中断)要求处理的时候,当前的进程可以被中断。为了防止共享的状态访问时被破坏,异步层使用的数据结构必须被保护(例如提升处理器级别或使用信号量)。

    × 例如,在一个操作系统内核中,硬件中断的服务时间很大程度上决定了对多级中断处理机构的需要。如果这个时间能够显著的减少,可以把所有的处理放到硬中断的层次上,这样就可以避免软中断的过度资源消耗。TCP/IP的实现中,就减少输入包的协议处理时间化费,让所有的包处理过程可以在两级中断机构实现。

    8.3 实现一个队列层
    队列层包含了一个同步控制点,缓存同步任务和异步任务之间交换的消息。在实现队列层的时候,要注意下面几点:

    × 并行控制。如果同步任务和异步任务的执行是并行的(如论使用多CPU还是硬件中断),为了避免争用,共享的队列的状态变化必须是连续的。因此,实现队列层的时候,经常使用并行控制机制,如信号量,互斥体和条件变量等。当消息在队列中插入或删除的时候,并行控制保证队列的内部数据结构不被破坏。

    ×层到层之间的流量控制。在队列层缓存消息,系统不能提供无限的资源。因此,必须控制同步和异步层之间传输的数据量。例如,在层到层的流控制下,避免同步层的数据量超过网络接口能够传输的极限。
    同步任务可以被阻塞。因此,可以使用下面的策略:如果其排队超过一定的量,可以让任务阻塞。当异步任务层把排队数降低到一定的水平,就可以重新唤醒同步任务继续执行。相对地,异步层地任务不能被阻塞,当处理过量地数据时,队列层要根据策略丢弃消息。这种情况下,如果使用了一个可靠的,面向连接的网络协议,发送者最终会发现传输超时,要求重新传输数据。

    ×数据拷贝消耗。一些系统(如BSD UNIX),把队列层放到了用户和内核之间的保护边界上。为了分离不同的保护域,一般使用拷贝数据的方法。然而,这增加了系统总线和内存的负担。当大数据量的消息传输的时候,这可能会降低很大的性能。
    一种减少数据拷贝的方式:分配一个专用的内存区,这个内存区被同步任务层和异步任务层共享[7]。这样,两层之间可以高效率的交换数据,不需要拷贝。例如 [8],存在一个I/O子系统,使用轮询的中断机制改进连续的I/O流处理,最小化跨边界数据传送消耗。这种方法同时提供了一个缓存管理系统,准许高效率的页影射,一个由用户进程,内核,设备使用的共享内存机构。

    9 例子代码
    这节说明两个使用半同步半异步模式的例子,这是在BSD UNIX中两个不同部分。这些例子将说明:半同步半异步模式如果让用户进程同步操作,让内核进程异步操作。第一个例子,在网络子系统中使用这个模式,在以太网上处理通过TCP/IP协议栈输入的数据。第二个例子,在文件系统上使用这个模式,在磁盘控制器上实现一个中断驱动的输出过程。

    9.1 BSD网络子系统的例子
    这个例子说明了如何把半主动半自动模式应用与read系统调用,实现同步的操作。异步地接收和处理到达网络接口的数据,同步完成read的调用。图一 说明了BSD UNIX中,这个模式的参与者和结构。关于BSD UNIX网络子系统的完整解释,请参考[9].

    9.1.1同步调用
    考虑一个用户进程,创建了一个被动模式的TCP流套接口,从连接的套接口描述子中接收TCP数据。对用户进程来说,read系统调用就是一个同步的操作,进程调用然后数据返回。当read被调用时,它进入操作系统内核,进入网络套接口的实现代码。最终,控制线程会进入soreceive函数,这个函数完成半同步部分的处理。soreceive负责把套接口队列的数据传递给用户。它必须能够处理多种类型的套接口(如数据报套接口和流套接口)。下面是简化后的样子,重点强调了同步和异步任务层之间的边界。
    /* Receive data from a socket. */
    int soreceive ( ... )
    {
        for (;;) {
            sblock (...); /* lock socket recv queue */
            /* mask off network interrupts to protect queue */
            s = splnet ();
            if (not enough data to satisfy read request) {
                sbunlock (...); /* unlock socket queue */
                /***** Note! *****
                * The following call forms the boundary
                * between the Sync and Async layers. */
                sbwait (...); /* wait for data */
                splx (s); /* drop splnet */
            }
            else
                break;
        }
        splx (s); /* drop splnet */
        /* copy data to user’s buffer at normal priority */
        uiomove (...);
        s = splnet (); /* mask off network interrupts */
        sbunlock (...); /* unlock socket queue */
        splx (s); /* restore spl */
        return (error code); /* returns 0 if no error */
    }

    上面的代码展示了同步的用户进程和异步的内核进程之间的边界。用户进程可以阻塞等待数据,内核却不能被挂起,因为其它的用户进程或硬件设备需要它的服务。

    soreceive处理read的请求有多种方式,这取决于套接口的属性和当前队列中的数据。

    ×完全同步。如果用户请求的数据已经在套接口队列中,数据将被立即取出,同步地完成操作。

    ×半同步半异步。如果请求的数据还没有到达内核,内核将调用sbwait函数,让用户进程阻塞至数据到达。

    一旦sbwait让进程进入随眠状态,操作系统的调度者会立即把上下文切换到其它进程运行。但原来的用户进程看起来,read系统调用是同步执行的。当包含数据的包到达内核时,将被异步处理,见9.1.2的描述。当足够多的数据到达队列后,内核将唤醒原来的进程进行处理。

    9.1.2 异步数据接收和协议处理
    当异步数据包到达网络接口的时候,半异步部分启动。所有输入的包在中断处理例程中处理。中断处理,没有进程上下文也没有控制线程,这期间是不能睡眠(被阻塞)的。因此,一个中断处理例程必须借用调用者所在的控制线程(例如,它的运行栈和寄存器)执行。BSD UNIX 内核使用这个策略,借用发起系统调用的用户线程。

    许多中断驱动的计算机给中断分配优先级。例如,在SPARC体系中,一共有15个中断级别,最低的是Level 1 最高的是Level 15。其它的处理器有不同的级别数(例如,Motorola 68030有7个中断级别)。在BSD UNIX中,设计了与机器无关的中断级别,叫SPL级别(SPL这个词原于古老的PDP-11机器上的UNIX系统),把每个处理器特有的级别将影射到这个SPL级别上。例如,最高的网络中断级别为SPLIMP,时钟中断为SPLCLOCK,最高的系统中断级别是SPLHIGH。每一个中断级别对应一个函数名字,这个函数完成处理器对应中断级别的设置。所以,函数splimp调用后,将把所有的网络硬件中断排除在外。所有的spl*函数返回上一个处理器级别,这个值供恢复使用。

    传统的BSD UNIX版本使用两级的中断结构进行数据包的处理。硬件级关键处理在高级别(SPLIMP)上完成,较不关键的软件处理在低级别(SPLNET)上完成。这种两个级别的体系,防止软件协议处理的过度消耗对硬中断处理造成延时。两个级别的包处理体系自然分成了两部分:硬件相关的处理和软件协议处理。当一个包到达网络接口时,产生那个接口级别的中断,所有网络接口的中断优先级<=SPLIMP。操作系统处理硬件的中断,把进入的数据包交给协议层处理(如IP协议)。当硬中断的处理完成,并且没有其它的未处理完的高级别中断,较低级别的软件中断(SPLNET)开始进行剩余的协议的处理。BSD的内核被小心的设计,保证在软中断处理的过程中,如果又发生硬中断,不会造成数据丢失和缓存被破坏的情况。

    考虑一个例子,一个主机安装了AMD LANCE的以太网卡,这个设备的驱动名字叫“le”。当数据到达的时候,中断处理中lerint函数被调用。它的工作是确认和清除中断,从包中提取数据,把数据拷贝到名字为mbuf的内存缓存区。如下:
    int lerint (...)
    {
    /* perform hardware sanity checks */
    while (inbound buffers to process) {
         /* get length and clear interrupt ... */
         /* read the packet into mbufs */
         ether_input (interface, ether_type, packet);
         /* free buffer */
    }
    }

    mbuf被传递给以太函数ether_init
    int ether_input (char *intf, int etype, struct mbuf *packet)
    {
       switch (etype) {
          case ETHERTYPE_IP:
          /* schedule network interrupt */
           schednetisr (NETISR_IP);
           inq = &ipintrq;
          break;
          /* etc... */
       }
       s = splimp ();
       /* Try to insert the packet onto the IP queue. */
       if (IF_QFULL (inq)) {
          /* queue full, drop packet */
          IF_DROP (inq);
          m_freem (packet);
       }else
          /* queue packet for net interrupt */
          IF_ENQUEUE (inq, m);
          splx (s);
    }

    每一个网络协议拥有一个数据包队列(例如,IP 包队列),ether_input函数先检测应该使用哪一个网络协议,把数据包入队到正确的协议的队列中。然后,一个软中断发生,这个中断是较低的SPLNET级别。到了这里,硬件中断的处理已经完成,中断服务例程退出。

    硬中断完成后,当没有更高级别中断的时候,SPLNET级别的软中断发生。如果输入的数据包是一个IP数据包,内核将调用IP中断例程(ipintr)。在这个例程中进行IP协议的处理(如:消息头解析,包转发,分解和重组)。如果数据包确定要发给本机的进程,把数据包传递给传输层。传输层会进行更多的协议处理(如TCP协议级的重组和确认)。最终传输层把数据放到套接口队列中,调用sbwakeup,这个调用将唤醒原来的用户进程,这个进程之前在 soreceive调用中阻塞。当这些工作完成,软中断的包处理完成。

    下面的代码对ipintr的处理流程进行了说明,从tcp_input,到sowakeup,组成了同步和异步层的边界,第一个函数ipintr,处理输入的数据包。
    int ipintr (...)
    {
       int s;
       struct mbuf *m;
       /* loop, until there are no more packets */
       for (;;) {
         s = splimp ();
         IF_DEQUEUE (&ipintrq, m); /* dequeue next packet */
         splx(s);
         if (m == 0) return; /* return if no more packets */
         if (packet not for us) {
             /* route and forward packet */
         } else {
            /* packet for us... reassemble */
            /* call protocol input, which is tcp_input() */
            (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
         }
       }
    }

    在我们的例子中,要处理的是一个TCP/IP的包,inetsw函数会根据判断结果调用tcp_input函数。这个函数处理一个输入的TCP数据包。
    int tcp_input (m, iphlen)
    {
       /* lots of complicated protocol processing... */
       /* We come here to pass data up to the user */
       sbappend (&so->so_rcv, m);
       sowakeup((so), &(so)->so_rcv);
       /* ... */
    }

    函数sowakeup将唤醒在read调用中睡眠的用户进程,这个进程之前一直在等待数据包的到达。在下面一节的讨论中将会看到,这个函数组成了同步和异步层的边界。

    9.1.3 同步阶段的完成
    当数据添加到队列后,如果有一个用户进程正在睡眠中等待这个数据,sowakeup函数将被调用。
    void sowakeup (so, sb)
    {
       /* ... */
       if (a user process is asleep on this queue) {
          /***** Note! *****
          The following call forms the boundary
          between the Async and Sync layers. */
          wakeup ((caddr_t) &sb->sb_cc);
       }
    }

    当一个进程陷入睡眠后,进程会和一个“Handle”绑定在一起。要唤醒这个睡眠的进程,wakeup以这个Handle为参数。一个等待事件的线程,一般使用和这个事件相关的数据结构的地址作为Handle。在我们的例子中,套接口接收队列的地址(sb->sc_cc)作为Handle。

    如果套接口队列上没有等待数据的进程,什么也不会发生。在我们的例子中,如9.1.1的说明,原来的进程阻塞在soreceive调用上。内核将要唤醒这个进程,它循环检测是否有足够多的数据到达供read使用。如果足够的数据到达,soreceive把数据拷贝到用户的缓冲区,系统调用read将会返回。

    对应用户进程,read调用看起来就是同步的。然而,这不过是半同步半异步模式造成的幻觉。特别地,异步进程和上下文的切换,在用户进程睡眠的过程中默默地发生。注意,内核不会阻塞,会一直在干活,总有一些东西在运行,哪怕是空闲进程行。

    9.2 磁盘控制器的例子
    这个例子说明了在BSD UNIX的文件子系统中使用半主动半被动模式的情况。上面的例子说明了这个模式中,数据在网络接口卡输入通过TCP/IP的协议栈一直传递到用户进程。下面这个例子将说明如何输出数据,数据来自用户的进程,通过了BSD UNIX 的I/O子系统, 最后到达磁盘。
    访问UNIX的磁盘类的存储设备,有两种方式。一种是通过/dev下的块设备文件,另外一种是通过字符设备文件。通过块设备文件访问的时候,要通过一个软件实现的磁盘块缓存区。与此相反,通过字符设备(叫“raw”I/O)访问的时候,会绕过缓存系统直接进行I/O操作。挂接一个文件系统前,Raw I/O往往用来做完整性检查。一些用户级别的数据库,想自己实现磁盘缓存机制,也会使用raw I/O。

    9.2.1 同步调用
    如果一个进程打开一个字符设备文件(例如:/dev/rdk0a),进行一个写动作,当设备驱动真正完成写动作后才会结束。这是半同步的处理部分,多数原始磁盘设备有一个write动作的执行入口点,入口点作为一个全局I/O的例程存储在全局的cdevsw向量中。如下所示。
    /* Do a write on a device for a user process. */
    int raw_write (dev_t dev, struct uio *uio)
    {
        return physio (cdevsw[major(dev)].d_strategy,
                       (struct buf *) NULL,
                       dev, B_WRITE, minphys, uio);
    }

    这个函数同步调用了physio,physio在用户进程的请求下完成物理I/O动作,物理I/O直接从裸设备写入到用户缓存区,绕过系统的高速缓存。如下实现
    int physio (int (*strategy)(),
                struct buf *bp,
                dev_t dev,
                int flags,
                u_int (*minphys)(),
                struct uio *uio)
    {
        struct iovec *iovp;
        struct proc *p = curproc;
        int error, done, i, nobuf, s, todo;
        /* ... */
        /* read and write, from above */
        flags &= B_READ | B_WRITE;
        bp->b_flags = B_BUSY | B_PHYS | B_RAW | flags;
        /* call driver's strategy to start the transfer */
        (*strategy) (bp);
        /***** Note! *****
         The following call forms the boundary
         between the Sync and Async layers. */
         while ((bp->b_flags & B_DONE) == 0)
             /* Wait for the transfer to complete */
             tsleep ((caddr_t) bp, PRIBIO + 1, "physio", 0);
         /* ... */
    }

    这个physio例程使用一个用户缓冲区,一个设备和设备的strategy函数指针作为参数。这个例程的任务是:发起一个读或写操作,然后立即返回。因为执行用户缓冲去的指针是用户提供的,第一步必须认。一旦确认,就把缓冲区封装到一个buf的结构体中。buf结构体的标志被设置说明其是一个写还是一个读操作。同时有标志说明了这是一个raw I/O的操作。当buf的结构体设置好,就传递到strategy,这个例程调度I/O操作并返回。下一步,physio睡眠直到I/O操作完成。

    9.2.2 异步处理
    带缓存的和raw I/O的请求,都是同步的进入设备的驱动,通过strategy函数。
    void strategy (struct buf *bp)
    {
    /* ... */
    s = splbio (); /* protect the queues */
    /* sort the buffer structure into the
    driver's queue (e.g., using disksort()) */
    if (drive is busy) { splx (s); return; }
          /* flow control is here.... if the
          drive is busy the request stays in the queue */
          /* start first request on the queue */
          /* done! */
          splx (s);
          return;
    }
    strategy被设计成通用的函数,大部分设备的I/O都使用这个接口。上面的例子假定驱动一次只处理一个请求。一个设备可能在一个时间处理多个请求,在这种情况下,需要使用多个列表保存哪一个缓存区是激活的,哪一个正在等待I/O。           
              
    9.2.3 同步完成阶段。
    当磁盘控制器完成操作后,会产生中断。这将触发一个中断处理例程,这个例程联系了同步任务层和异步任务层。如下面的代码
    int intr (void *v)
    {
         struct buf *bp;
         /* get current request into "bp" */
         /***** Note! *****
          The following ties the Async layer back
          into the Sync layer. */
         biodone (bp); /* Wakeup the sleep in physio(). */
         /* start next request on queue */
         return (1); /* done */
    }

    这个中断处理函数,完成中断服务并清除硬件中断。查看驱动的状态表检测一个I/O是不是完成。一个I/O的请求使用异步buf结构描述,一旦boidone函数被调用,将通知高一级的内核软件,write请求已经完成。这会导致进程的tsleep调用返回。

    10 变化
    使用半同步半异步模式的传统方式是:来自异步任务层的输入使用“pash-driver”的I/O,来自同步任务层的输入使用“pull-driver”的I/O,处理输出使用相反的方式。在一些系统中有下面的变化。

    ×组合异步通知和同步I/O。当数据在排队层缓存后,通知同步层。UNIX的SIGIO就是实现的这种信号驱动的I/O。在这种情况下,一个信号发给上层的用户进程,然后用户进程使用read读出数据。

    ×当要求异步处理的时候新产生线程。组合异步通知和同步I/O的另外一种方式,当异步事件发生的时候产生一个新的线程。

    × 在上层任务中使用异步I/O。一些系统扩展了原来的模型,准许把传递数据的通知发给上层任务。UNIX SYSTEM V 的第4版本使用这种方法扩展了信号接口。一个缓冲区指针作为信号处理函数的参数传递。Windows NT 使用重叠I/O的方式实现了相似的结构。这种结构中,一个异步事件中包含一个重叠的IO结构,结构中包含完成事件的标识和对应的数据。

    × 底层任务实现同步的I/O。单线程的操作系统(如BSD UNIX)。通常只对上层的任务使用混合的同步/异步模型。在这些系统中,底层的任务必须严格的使用异步I/O。如果使用线程实现上下文切换,系统准许在内核中使用同步的I/O。在高性能的媒体系统中,使用一个内核线程在固定的时间轮询共享内存特定的域,使用这种轮询的中断机制,可以减少上下文切换。
    如果异步任务层拥有自己的控制线程,他可以自动运行把消息通过队列层传递给同步任务层。微内核操作系统一般使用这种设计。在微内核中使用一个独立的进程和用户进程交换数据。

    11 Known Uses
    ×The BSD UNIX networking subsystem [1] and the original System V UNIX STREAMS communication framework [12] use the Half-Sync/Half-Async pattern to structure the concurrent I/O architecture of user processes and the OS kernel. All I/O in these kernels is asynchronous and triggered by interrupts. The Queueing layer is implemented by the Socket layer in BSD and by STREAM heads in System V STREAMS. I/O for user processes is synchronous. Most UNIX applications are developed as user processes that call the synchronous higher-level read/write interfaces. This design shields developers from the complexity of asynchronous OS handled by the kernel. There are provisions for notifications (via the SIGIO signal) that asynchronously trigger synchronous I/O.
    ×The multi-threaded version of Orbix 1.3 (MT-Orbix) [13] uses several variations of the Half-Sync/Half-Async pattern to dispatch CORBA remote operations in a concurrent server. In the Asynchronous layer of MTOrbix a separate thread is associated with each HANDLE that is connected to a client. Each thread blocks synchronously readingCORBArequests from the client. When a request is received it is formatted and then enqueued at the Queueing layer. An active object thread in the Synchronous layer then wakes up, dequeues the request, and processes it to completion by performing an upcall on the CORBA object implementation.
    ×The Motorola Iridium system uses the Half-Sync/Half-Async pattern in an application-level Gateway that routes messages between satellites and ground control stations [14]. The Iridium Gateway implements the Half-Sync/Half-Async pattern with the ADAPTIVE Service eXecutive (ASX) framework [15]. The Reactor [6] class category from the ASX framework implements an object-oriented demultiplexing and dispatching mechanism that handles events asynchronously. The ASX Message Queue class implements the Queueing layer, and the ASX Task class implements active objects in the Synchronous task layer.
    ×The Conduit communication framework [16] from the Choices OS project [17] implements an object-oriented version of the Half-Sync/Half-Async pattern. User processes are synchronous active objects, an Adapter Conduit serves as the Queueing layer, and the Conduit micro-kernel operates asynchronously. 

    12 Related Patterns
    ×The Synchronous task layer uses the Active Object pattern[3].(这个模式,我也已经翻译了)
    ×The Asynchronous task layer may use the Reactor pattern [6] to demultiplex events from multiple sources of events.
    ×The Queueing layer provides a Facade [18] that simplifies the interface to the Asynchronous task layer of the system.
    ×The Queueing layer is also a Mediator [18] that coordinates the exchange of data between the Asynchronous and Synchronous task layers.


    Acknowledgements
    We would like to thank Lorrie Cranor and Paul McKenney for comments and suggestions for improving this paper.

    References

    [1] S. J. Leffler,M.McKusick,M. Karels, and J.Quarterman, The Design and Implementation of the 4.3BSD UNIX Operating System. Addison-Wesley, 1989.

    [2] D. C. Schmidt and T. Suda, "Measuring the Performance of Parallel Message-based Process Architectures," in Proceedings of the Conference on Computer Communications (INFOCOM),(Boston, MA), pp. 624-633, IEEE, April 1995.

    [3] R. G. Lavender and D. C. Schmidt, "Active Object: an Object Behavioral Pattern for Concurrent Programming," in Proceedings of the 2nd Annual Conference on the Pattern Languages of Programs, (Monticello, Illinois), pp. 1-7, September 1995.

    [4] N. C. Hutchinson and L. L. Peterson, "The x-kernel: An Architecture for ImplementingNetwork Protocols," IEEE Transactions on Software Engineering, vol. 17, pp. 64-76, January 1991.

    [5] D. C. Schmidt, T. H. Harrison, and E. Al-Shaer, "Object-Oriented Components for High-speed Network Programming,"in Proceedings of the 1st Conference on Object-Oriented Technologies and Systems, (Monterey, CA),USENIX, June 1995.

    [6] D. C. Schmidt, "Reactor: An Object Behavioral Pattern for Concurrent Event Demultiplexing and Event Handler Dispatching," in Pattern Languages of Program Design (J. O.Coplien and D. C. Schmidt, eds.), Reading, MA: Addison-Wesley, 1995.

    [7] P. Druschel and L. L. Peterson, "Fbufs: A High-Bandwidth Cross-Domain Transfer Facility," in Proceedings of the 14th Symposium on Operating System Principles (SOSP), Dec.1993.

    [8] C. Cranor and G. Parulkar, Design of Universal Continuous Media I/O, in Proceedings of the 5th InternationalWorkshop on Network and Operating Systems Support for Digital Audio and Video (NOSSDAV (Durham, New Hampshire),pp. 83-86, Apr. 1995.

    [9] W. R. Stevens, TCP/IP Illustrated, Volume 2. Reading, Massachusetts:AddisonWesley, 1993.

    [10] H. Custer, Inside Windows NT. Redmond, Washington: MicrosoftPress, 1993.

    [11] D. L. Black, "Scheduling Support for Concurrency and Parallelism in the Mach Operating System, IEEE Computer,vol. 23, pp. 23-33,May 1990.

    [12] D. Ritchie, A Stream Input-Output System,"AT&TBell Labs Technical Journal, vol. 63, pp. 311-314,Oct. 1984.

    [13] C. Horn, "The Orbix Architecture," tech. rep., IONA Technologies,August 1993.

    [14] D. C. Schmidt, A Family of Design Patterns for Applicationlevel Gateways," The Theory and Practice of Object Systems (Special Issue on Patterns and Pattern Languages), vol. 2, no. 1, 1996.

    [15] D. C. Schmidt, "ACE: an Object-Oriented Framework for Developing Distributed Applications, Proceedings of the 6th USENIX C++ Technical Conference, (Cambridge, Massachusetts),USENIX Association, April 1994.

    [16] J. M. Zweig, "The Conduit: a Communication Abstraction in C++," in Proceedings of the 2nd USENIX C++ Conference,pp. 191-203,USENIX Association, April 1990.

    [17] R. Campbell, N. Islam, D. Raila, and P. Madany, "Designing and Implementing Choices: an Object-Oriented System in C++," Communications of the ACM, vol. 36, pp. 117-126,Sept. 1993.

    [18] E. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software.Reading,MA: Addison-Wesley, 1995.
    展开全文
  • 同步和异步执行模式 ODBC2.0访问数据库时,有同步执行模式异步执行模式之分。 所谓同步执行模式,是指语句在同步执行模式下,将始终保持对程序流的控制,直至程序结束。例如查询操作,客户机上的应用程序在向...

    同步和异步执行模式 
      ODBC2.0访问数据库时,有同步执行模式与异步执行模式之分。 
      所谓同步执行模式,是指语句在同步执行模式下,将始终保持对程序流的控制,直至程序结束。例如查询操作,客户机上的应用程序在向服务器发出查询操作的指令后,将一直等待服务器将查询结果返回客户机端后,才继续进行下一步操作。

     所谓异步执行模式,是指语句在异步执行模式下,各语句执行结束的顺序与语句执行开始的顺序并不一定相同。例如查询操作,客户机上的应用程序在向服务器发出了查询操作的指令后,将立刻执行查询语句的下一条语句,而不需要等到服务器将查询结果返回客户机端后,才继续进行下一步操作。 

      在一些应用程序开发工具中,在其提供使用数据控制项和数据库对象变量进行编程的同时,并没有很好地考虑到同步执行模式与异步执行模式的重要区别。为了使程序运行速度更快,其语句执行的缺省模式为异步模式。对于一般程序员来说,如果他对同步执行模式与异步执行模式不了解的话,他往往会在对服务器发出一个操作语句(查询或读取一条记录等操作)后,立刻引用服务器返回的执行结果,或者对该结果进行下一步操作;在异步执行模式下,客户机上的后续语句是在该操作语句发出后接着执行的,但由于各种原因,服务器不一定能执行完该操作语句,并在后续语句执行前将结果返回客户机。因此,后续语句在引用前一操作语句的执行结果时,往往会因为该执行结果并不存在而引用了错误的值,造成系统错误或死锁。

      解决上面所提到的问题,可以采取以下两种方案: 

      ①利用ODBC2.0API,将语句执行状态设置为同步执行模式。ODBC2.0API中,函数SQLSetStmtOption()的功能是设置同步或异步执行模式。我们可以采用以下语句,将语句执行状态设置为同步执行模式: 
    iRetCodeΚSQLSetStmtOption(hStmt,SQL-ASYNC-ENABLE,0) 
    其中,hStmt是一有效的语句句柄,常数SQL-ASYNC-ENABLE是所要设置的选项,参数0表示该选项(即异步执行模式)关闭。如果iRetCode返回SQL-SUCCESS,则表示语句执行状态已被设置为同步执行模式。 
      ②利用ODBC2.0API,将语句执行状态设置为异步执行模式,然后在程序中不断查询一个操作语句是否已经执行完毕。 
      这些函数第一次调用后,将返回值SQL-STILL-EXECUTING,这时应用程序将继续执行后续语句。过了一段时间后,应该再次调用原函数,而且要注意:实参数应传入与第一次调用时相同的语句句柄,其他参数也应一样(但会被忽略)。如果函数返回值为SQL-SUCCESS,则表明该语句已经执行完毕;如果函数返回SQL-STILL-EXECUTING,则表明该语句仍在执行中。 

      我们可以用一个简单的例子说明如下: 

    iRetCodeΚSQLSetStmtOption(hStmt,SQL-ASYNC-ENABLE,1) 
    ′置语句执行模式为异步执行模式 
    iRetCodeΚSQLExecDirect(hStmt,″SELECT*FROMemployees″,23) 
    ......′执行其他操作 
    iRetCodeΚSQLExecDirect(hStmt,″SELECT*FROMemployees″,23) 
    ′判断SQLExecDirect()是否已执行完毕 
    If(iRetCodeΚSQL-STILL-EXECUTING)Then 
    ......′该语句未执行完,继续执行其他操作 
    Else 
    If(iRetCodeΚSQL-SUCCESS)Then 
    ......′该语句已执行完,可对语句操作结果进行处理 
    EndIf 
    EndIf

      同步执行模式可以简化程序编制的复杂性,对ODBC2.0API不十分熟悉的程序员,可以不用过多地了解比较复杂的ODBC2.0API,而只需使用数据控制项和数据库对象变量来编写应用程序,使开发效率大大提高,但程序运行速度比不上异步执行模式的速度。 

      异步执行模式虽然在编程序时十分复杂,但在这种模式下可以进行多任务并行执行,使执行效率大大提高。

    展开全文
  • 直接上图了,规范性先忽略。 ASIO同步模式。这个相对简单 ASIO异步模式

    直接上图了,规范性先忽略。

    ASIO同步模式。这个相对简单




    ASIO异步模式


    展开全文
  • 电子政务-信息传递兼具同步模式和异步模式的电商系统.zip
  • 电信设备-在同步和异步通信模式之间过渡的方法系统.zip
  • ajax同步模式和异步模式的区别就是在于,xhr.open()方法第3个参数传入的bool值的区别,xhr.open()方法第3个参数的作用就是设置此次请求是否采用异步模式执行,默认为true ,那么同步模式xhr.open()方法第3个参数值...

    ajax同步模式和异步模式的区别就是在于,xhr.open()方法第3个参数传入的bool值的区别,xhr.open()方法第3个参数的作用就是设置此次请求是否采用异步模式执行,默认为true ,那么同步模式xhr.open()方法第3个参数值就是false了。

    ajax同步模式和异步模式的区别

    1.ajax异步模式:hr.open()方法第3个参数值为true(默认值)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    console.log('before ajax')

    var xhr = new XMLHttpRequest()

    // 默认第三个参数为 true 意味着采用异步方式执行

    xhr.open('GET''./test.php'true)

    xhr.send(null)

    xhr.onreadystatechange = function () {

    if (this.readyState === 4) {

    // 这里的代码最后执行

    console.log('request done') 10}

    }

    console.log('after ajax')

    2.ajax同步模式:hr.open()方法第3个参数值为false,以下这个例子采用同步方式执行,则代码会卡死在这一步:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    console.log('before ajax')

    var xhr = new XMLHttpRequest()

    // 同步方式

    xhr.open('GET''./test.php'false)

    // 同步方式 执行需要 先注册事件再调用 send,否则 readystatechange 无法触发

    xhr.onreadystatechange = function () {

    if (this.readyState === 4) {

    // 这里的代码最后执行

    console.log('request done') 10}

    }

    xhr.send(null)

    console.log('after ajax')

      特别注意:同步模式和异步模式的差异,就是一定在发送请求之前注册事件,不管同步或者异步,为了让这个事件可以更加可靠一定要触发,一定是先注册了事件,切记不要使用同步模式。


    原文地址:http://tangjiusheng.com/ajax/149.html

    展开全文
  • 同步和异步的区别

    万次阅读 多人点赞 2018-10-25 19:10:42
    原文地址:同步和异步,区别 同步同步的思想是:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的...
  • GPU: 多GPU训练的同步模式和异步模式

    千次阅读 2018-10-05 21:11:13
    常用的并行化深度学习模型训练方式有两种:同步模式和异步模式。 下面将介绍这两种模式的工作方式及其优劣。 如下图,深度学习模型的训练是一个迭代的过程。 在每一轮迭代中,前向传播算法会根据当前参数的取值...
  • 设计模式大部分都是扯蛋的,真正有用的不多,广泛应用的更少寥寥无几,半同步异步(Half-Sync/Half-Async)正是其中之一 一: 同步和异步的问题 同步: 编码简单,逻辑清晰, 但效率低 异步: 效率高,但结构复杂,需处理各种...
  • 对于ajax我们应该知道ajax是主要用来在前端页面中向服务器后端请求数据,ajax中根据async的值不同分为同步(async = false)和异步(async = true)两种执行方式,那么,ajax的同步和异步请求两种方式有什么区别呢?...
  • 同步和异步

    千次阅读 2018-07-01 22:50:18
    同步和异步通常用来形容方法的调用方式。同步方法表明调用一旦开始,调用者必须等待方法执行完成,才能继续执行后续方法。异步方法表明,方法一旦开始,立即返回,调用者无需等待其中方法执行完成,就可以继续执行...
  • 同步/半异步(half-sync/half-async): 在网上一份资料中引用了一本貌似很经典的书里的比喻:” 许多餐厅使用 半同步/半异步 模式的变体。例如,餐厅常常雇佣一个领班负责迎接顾客,并在餐厅繁忙时留意给顾客安排...
  • 理解javascript的同步异步模式

    千次阅读 2016-03-23 11:34:38
    你可能知道,Javascript语言的执行...这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是
  • 高效的半同步/半异步模式的实现

    千次阅读 2018-03-16 21:19:57
    先介绍一下半同步/半异步模式:首先半同步/半异步模式中的同步和异步前面的IO模型中的同步和异步是完全不用的概念。在IO模型中,同步和异步区分的是内核向应用程序通知的是何种IO事件(是就绪事件还是完成事件),...
  • JS同步和异步 一、单线程模型 JavaScript是一门单线程的语言,所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务。 看下面一段代码在浏览器中的执行的...
  • Winsock的同步异步模式

    2016-10-31 22:08:25
    同步&异步同步对应阻塞方式,异步对应非阻塞方式。 同步意思就是,我不但要发送信息,还要等到信息被处理完才走,比较负责,易用,但效率低。异步套接字使用复杂,但效率高。 SendMessage函数就是同步函数,Post...
  • 同步和异步的概念

    千次阅读 2015-03-07 10:26:23
    昨天被问到了同步和异步的概念,当时没有多想,回答的时候就举了个例子,说是比方说以时间序列为基准,同步是一定要到了某个时间点才能执行,异步则在到达那个时间点之前就可以执行,所以二者存在时间上的延迟区别。...
  • 串口 同步和异步 理解

    万次阅读 多人点赞 2015-09-14 14:29:02
    本文主要三大块:一,串口同步和异步在地产通行上的区别(这部分点到为止,不是主要探讨内容,有个基本理解即可)。  二,串口同步和异步编程实例及详解(主要部分)。  三,串口同步和异步的作用(着眼当下,理解...
  • 而在C++开发中,同步模式应该是主流,如果一定要使用异步模式加回调,可以参考Using IXMLHTTPRequest onreadystatechange from C++一文。 下面是采用异步模式获取远程主机上RSS文件的代码,关键的地方是设置一个回调...
  • 事件处理模式和并发模型的区别 这篇要介绍的事件处理模式有reactor和proactor;而要介绍的并发模型有半同步/反应堆和半同步异步 事件处理模式,指的是...TODO 事件处理模式 事件处理模式,本文介绍的有两种,是...
  • 同步/半异步模式

    2017-02-15 11:19:03
    同步/半异步模式的结构遵循分层模式,包括四层:同步服务层 同步服务层:完成高层处理服务。同步层中的服务在独立的操作情况下可以阻塞现成或进程。 异步服务层:进行低层处理服务。这些低层处理服务通常由一个...
  • 支持同步和异步阶段的无障碍管道模式实现 介绍 管道 JS 允许您在 Javascript 应用程序中创建可重用管道的同时实现管道模式。 您可以一次创建由一个或多个阶段组成的管道,然后使用不同的有效负载处理它们。 管道...
  • 同步/半异步模式、半同步/半反应堆模式、相对高效的半同步/半异步模式、领导者/追随者模式
  • 同步异步模式:出现原因: 异步线程执行效率高,但是编写复杂,同步线程效率低,但是逻辑简单。服务器要求好的实时性同时处理多用户的请求,英雌采用两者结合的形式。 具体情况: 过程: 异步线程见听到...
  • 同步和异步问题

    千次阅读 2020-05-04 14:14:42
    一、什么叫同步异步: 1、同步同步操作没有结束之前,后面的代码是无法执行的。 2、异步异步操作没有结束之前,后面的代码是可以执行的。 二、哪些是异步问题: 1、计时函数:setTimeout()、setInterval()。 2...
  • 计算机同步和异步

    2020-12-08 10:45:02
    同步是阻塞模式同步是按顺序执行,执行完一个再执行下一个,需要等待,协调运行; 异步 异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,...
  • 行业资料-电子功用-具有同步操作模式和异步操作模式的电源.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 268,455
精华内容 107,382
关键字:

同步和异步模式