同步的“call-order-aware”方法返回值

时间:2011-01-07 02:08:05

标签: .net multithreading thread-safety

我有一个方法可以向设备发送3个Web请求,这会让它发送短信。 第一个请求分别设置了sms接收者和消息体。第三个触发调度。

很明显,这种方法必须同步,因为竞争调用将完全搞乱短信配置过程。

这当然可以很好地解决:

private object _smsLock  
private bool SendSmsSync(string recipientNumber, string body)  
{  
    lock(_smsLock)  
    {  
        // 3 web requests are sent here  
        // false is returned if something goes wrong
        return true;
    }  
}

然而,这个解决方案的缺点是我们完全无法控制同时进行的呼叫的顺序。

包括Queue,ManualResetEvents和线程在内的大量代码当然可以实现。但我仍然想知道是否有人知道更简单的方法。

讨论:))

2 个答案:

答案 0 :(得分:1)

这似乎是保护邮件发送的合理方法。它会阻止消息本身出现故障。

如果需要跨多个消息进行同步,则一个选项是使用生产者/消费者方案。这将允许你有一个单独的线程,除了按顺序抽出这些消息之外什么都不做。

public class Sms
{
    public class SmsMessage
    {
        public int RecipientNumber { get; private set; }
        public string Body { get; private set; }
        public Sms(int recipient, string body) 
        { 
           this.RecipientNumber = recipient;
           this.Body = body;
        }
    }

    // Include your code above...

    private BlockingCollection<SmsMessage> messageQueue = new BlockingCollection<SmsMessage>();

     public void Send(SmsMessage message)
     {
           messageQueue.Add(message);
     }

     // Permanently stop sending messages...
     public void Stop()
     {
           messageQueue.CompleteAdding();
     }

     public Sms()
     {
         // Spawn a thread to pump messages as they arrive
         Task.Factory.StartNew( () =>
             {
                  foreach(var message in messageQueue.GetConsumingEnumerable())
                      SendSmsSync(message.RecipientNumber, message.Body);
             }, TaskCreationOptions.LongRunning);
     }
}

有了这个,你可以创建一个Sms实例,并调用Send来排队一条消息。消息将始终按顺序发送。

此外,这应该不需要上面的锁定,因为消息总是在一个消费者线程中发送。

答案 1 :(得分:0)

最简单和最合乎逻辑的答案当然应该是“不要那样做”。

即:如果你需要按顺序进行三次调用*,不要将它们放在单独的线程上 - 只需按顺序编写代码即可。

(*好的,所以第一个和第二个可以并行化,但为什么呢?)