使两个函数调用原子?

时间:2015-07-14 05:29:40

标签: f#

我对块队列https://msdn.microsoft.com/en-us/library/vstudio/hh297096(v=vs.100).aspx有以下用法。如何确保某些函数执行是原子的?

以下是一个可测试的例子。

// ----------------------------------------------------------------------------
// Blocking queue agent
// ----------------------------------------------------------------------------

open System
open System.Collections.Generic

type Agent<'T> = MailboxProcessor<'T>

type internal BlockingAgentMessage<'T> = 
  | Add of 'T * AsyncReplyChannel<unit> 
  | Get of AsyncReplyChannel<'T>

/// Agent that implements an asynchronous blocking queue
type BlockingQueueAgent<'T>(maxLength) =
  let agent = Agent.Start(fun agent ->

    let queue = new Queue<_>()

    let rec emptyQueue() = 
      agent.Scan(fun msg ->
        match msg with 
        | Add(value, reply) -> Some(enqueueAndContinue(value, reply))
        | _ -> None )
    and fullQueue() = 
      agent.Scan(fun msg ->
        match msg with 
        | Get(reply) -> Some(dequeueAndContinue(reply))
        | _ -> None )
    and runningQueue() = async {
      let! msg = agent.Receive()
      match msg with 
      | Add(value, reply) -> return! enqueueAndContinue(value, reply)
      | Get(reply) -> return! dequeueAndContinue(reply) }

    and enqueueAndContinue (value, reply) = async {
      reply.Reply() 
      queue.Enqueue(value)
      return! chooseState() }
    and dequeueAndContinue (reply) = async {
      reply.Reply(queue.Dequeue())
      return! chooseState() }
    and chooseState() = 
      if queue.Count = 0 then emptyQueue()
      elif queue.Count < maxLength then runningQueue()
      else fullQueue()

    // Start with an empty queue
    emptyQueue() )

  /// Asynchronously adds item to the queue. The operation ends when
  /// there is a place for the item. If the queue is full, the operation
  /// will block until some items are removed.
  member x.AsyncAdd(v:'T, ?timeout) = 
    agent.PostAndAsyncReply((fun ch -> Add(v, ch)), ?timeout=timeout)

  /// Asynchronously gets item from the queue. If there are no items
  /// in the queue, the operation will block unitl items are added.
  member x.AsyncGet(?timeout) = 
    agent.PostAndAsyncReply(Get, ?timeout=timeout)


// ----------------------------------------------------------------------------
open System.Threading

let ag = new BlockingQueueAgent<int>(3)

async { 
  for i in 0 .. 10 do 

    // The following 5 lines need to be atomic 
    printfn "1. before add %d" i
    Thread.Sleep(1000)
    printfn "2. before add %d" i
    Thread.Sleep(1000)
    printfn "3. before add %d" i

    do! ag.AsyncAdd(i)
    printfn "Added %d" i }
|> Async.Start

async { 
  while true do
    do! Async.Sleep(1000)
    let! v = ag.AsyncGet()

    // The following 5 lines need to be atomic
    printfn "1. process %d" v
    Thread.Sleep(1000)
    printfn "2. process  %d" v
    Thread.Sleep(1000)
    printfn "3. process  %d" v

    printfn "Got %d" v }
|> Async.Start

1 个答案:

答案 0 :(得分:1)

您可以使用Mutex

在.NET中,如果需要进程间锁定,则可以使用Mutex class

如果您只需要在AppDomain中进行同步,那么a lock就足够了吗?