预留剧院座位

时间:2016-11-08 15:52:40

标签: c# asp.net asp.net-mvc multithreading

想想看电影票。有x个开放式座位,当你来到现场时,我想预留一个座位一段时间。

我有一个私有内部API和一个公共API。公共API将通过调用内部API然后将该席位置于“正在预订”状态来响应寻求预订座位的应用程序。

我的问题是我偶尔会有两个人预订同一个座位,导致一个人输入所有信息,然后无法完成注册。

我试图让我的代码线程安全,但仍然得到同一个席位的奇怪重复分配。

我从我的“预约”方法调用状态更新:

VisitStatusChangeResult visit_status_change_result = await ReserveSlotByLockedStatusUpdate(first_empty_seat);

这是状态更新方法,我尝试使用SemaphoreSlim添加线程安全性:

private static SemaphoreSlim m_ReserveOnlineSlotStatusUpdateSemaphore = new SemaphoreSlim(initialCount: 1, maxCount: 1);


private async Task<VisitStatusChangeResult> ReserveSlotByLockedStatusUpdate(VisitQueryResult first_empty_seat)
{
  await m_ReserveOnlineSlotStatusUpdateSemaphore.WaitAsync();

  try
  {
    return await ChangeStatus(new VisitStatusUpdateModel
    {
      VisitID = first_empty_seat.ID,
      CurrentVisitStatusID = first_empty_online_visit.VisitStatusID,
      NewVisitStatusID = (int)VisitStatuses.BeingBooked
    });
  }
  finally
  {
    m_ReserveOnlineSlotStatusUpdateSemaphore.Release();
  }

}

我错过了一些即使SemaphoreSlim等待的事情,我可以让两个人抓住同一个座位吗?

1 个答案:

答案 0 :(得分:1)

首先,使用内存中的锁来保护对数据库资源的并行访问并不是一个好主意 - 每个数据库都有自己的工具来处理这些事情。在这种情况下,您很可能必须使用乐观并发,大致如下:

update Visit set VisitStatusID = BeingBooked, ClientID = CurrentClientID where VisitStatusID = Free

所以你知道现在正在预订这个座位,而且,如果发生这个座位已经不是免费的话 - 这个陈述将返回0(0行修改)。您应该检查并采取相应措施(通知客户已经采取了这个座位并刷新座位)。

其次,你的锁无论如何都没有效果。没有什么能阻止两个客户端一个接一个地调用ReserveSlotByLockedStatusUpdate ,并且仍然遇到麻烦,因为他们都会保留相同的席位(除非你实现上面的乐观并发)。 / p>