【问题标题】:Reserving A Theater Seat预订剧院座位
【发布时间】:2016-11-08 15:52:39
【问题描述】:

考虑在电影中订票。有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 等待,我也可以让两个人抢同一个座位?

【问题讨论】:

  • 您是否将预订信息存储在数据库中?如果是,为什么允许(在数据库级别)发生这种情况?
  • 是的,每个座位都是数据库中的一排,fk 为VisitStatusID,这就是设置为“正在预订”的内容,所以我们知道座位是保留的,直到客户预订座位,离开预订应用程序,或者他们用完了时间。

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


【解决方案1】:

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

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

所以您知道现在预订了这个座位,而且,如果发生这种情况,这个座位已经不是空闲的 - 此语句将返回 0(修改了 0 行)。您应该对此进行检查并采取相应措施(通知客户该席位已被占用并刷新席位)。

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

【讨论】:

  • 感谢您抽出宝贵时间回答。我们确实会检查座位上的状态,以便在更新前下次尝试更新状态,但这仍然会失败吗?如果有帮助,我们正在使用 mysql。
  • 是的,因为在您的检查和更新之间,行可能已经被更新(除非您执行诸如对有问题的行进行数据库行锁定之类的操作)。但是,如果您只是进行常规选择,然后进行更新 - 这是不安全的。
  • 因此,由于这种外部访问(数据库),我应该寻求通过数据库并发方法来处理这个问题。如果我没有访问数据库,我可以像我尝试过的那样留在线程安全操作中吗?
  • 是的(虽然最好使用常规锁而不是信号量 - 如果所有内容都在内存中,则不需要异步执行)。
  • 顺便说一下,如果您使用实体框架 - 它支持开箱即用的乐观并发更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-04
  • 1970-01-01
  • 1970-01-01
  • 2022-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多