C# 预定剧院座位

C# 预定剧院座位,c#,asp.net,asp.net-mvc,multithreading,C#,Asp.net,Asp.net Mvc,Multithreading,想一想订一张电影票。有x个开放的座位,当你来到这个网站,我想预订一个座位一段时间 我有一个私有的内部API和一个公共API。公共API将通过调用内部API来响应寻求预订座位的应用程序,然后将该座位置于“已预订”状态 我的问题是,我偶尔会有两个人预订同一个座位,这会导致一个人输入他们的所有信息,然后无法完成他们的注册 我试图使我的代码线程安全,但仍然得到相同座位的奇怪重复分配 我通过“保留”方法调用我的状态更新,如下所示: VisitStatusChangeResult visit_status_

想一想订一张电影票。有x个开放的座位,当你来到这个网站,我想预订一个座位一段时间

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

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

我试图使我的代码线程安全,但仍然得到相同座位的奇怪重复分配

我通过“保留”方法调用我的状态更新,如下所示:

VisitStatusChangeResult visit_status_change_result=wait ReserveSlottByLockedStatus Update(第一个座位是空的)

这是我试图使用信号量LIM将线程安全性添加到的状态更新方法:

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();
  }

}
private static SemaphoreSlim m_reserveOnline slotstatusupdatesemaphore=new SemaphoreSlim(initialCount:1,maxCount:1);
专用异步任务保留SlotByLockedStatus更新(VisitQueryResult first\u empty\u席位)
{
等待m_ReserveOnlinesSlotStatusUpdateSemaphore.WaitAsync();
尝试
{
返回等待更改状态(新的VisitStatusUpdateModel
{
VisitID=第一个空座位ID,
CurrentVisitStatusID=第一个\u空\u在线\u访问。VisitStatusID,
NewVisitStatusID=(int)VisitStatuses.BeingBooked
});
}
最后
{
m_ReserveOnlinesSlotStatusUpdateSemaphore.Release();
}
}

我是否错过了一些即使有信号灯Lim在等待,我也可以让两个人抢同一个座位的地方

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

update Visit set VisitStatusID = BeingBooked, ClientID = CurrentClientID where VisitStatusID = Free
所以您知道谁现在正在预订这个座位,而且,如果发生这种情况,这个座位已经没有空了,那么这个语句将返回0(修改了0行)。您应该对此进行检查并采取相应的行动(通知客户此座位已被占用并刷新座位)


第二,你的锁无论如何都没有效果。没有什么可以阻止两个客户端依次调用
ReserveSlotByLockedStatus Update
,但仍然会遇到问题,因为它们都会保留相同的席位(除非您实现上述乐观并发)。

您是否将预订信息存储在数据库中?如果是,为什么允许(在数据库级别)出现这种情况?是的,每个座位在数据库中都是一行,fk为
VisitStatusID
,这是设置为“BeingBooked”的,因此我们知道在客户预订座位、离开预订应用程序之前,座位是保留的,或者他们没时间了。谢谢你花时间回答。我们会在更新前检查座椅上的状态,以便下次尝试更新状态,但这仍然会失败?如果有帮助的话,我们正在使用mysql。是的,因为在您的检查和更新之间,行可能已经被更新了(除非您在有问题的行上执行数据库行锁定之类的操作)。但是,如果你只是在更新之后进行常规选择,这是不安全的。因此,由于这种外部访问(DB),我应该通过DB Concurence方法来处理这个问题。如果我没有点击DB,我可以像我尝试过的那样保持在线程安全操作中?是的(不过最好使用常规锁而不是信号量-如果所有的都在内存中,你就不需要异步执行)。顺便说一句,如果你使用实体框架-它支持开箱即用的乐观并发更新。