LockComponent.cs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. using System;
  2. using System.Threading.Tasks;
  3. namespace Model
  4. {
  5. public enum LockStatus
  6. {
  7. LockedNot,
  8. LockRequesting,
  9. Locked,
  10. }
  11. [ObjectEvent]
  12. public class LockComponentEvent : ObjectEvent<LockComponent>, IAwake<string>
  13. {
  14. public void Awake(string a)
  15. {
  16. this.Get().Awake(a);
  17. }
  18. }
  19. /// <summary>
  20. /// 分布式锁组件,Unit对象可能在不同进程上有镜像,访问该对象的时候需要对他加锁
  21. /// </summary>
  22. public class LockComponent: Component
  23. {
  24. private LockStatus status = LockStatus.LockedNot;
  25. private string address;
  26. private int lockCount;
  27. private readonly EQueue<TaskCompletionSource<bool>> queue = new EQueue<TaskCompletionSource<bool>>();
  28. public void Awake(string addr)
  29. {
  30. this.address = addr;
  31. }
  32. public async Task Lock()
  33. {
  34. ++this.lockCount;
  35. if (this.status == LockStatus.Locked)
  36. {
  37. return;
  38. }
  39. if (this.status == LockStatus.LockRequesting)
  40. {
  41. await WaitLock();
  42. return;
  43. }
  44. this.status = LockStatus.LockRequesting;
  45. // 真身直接本地请求锁,镜像需要调用Rpc获取锁
  46. MasterComponent masterComponent = this.GetComponent<MasterComponent>();
  47. if (masterComponent != null)
  48. {
  49. await masterComponent.Lock(this.address);
  50. }
  51. else
  52. {
  53. RequestLock();
  54. await WaitLock();
  55. }
  56. }
  57. private Task<bool> WaitLock()
  58. {
  59. if (this.status == LockStatus.Locked)
  60. {
  61. return Task.FromResult(true);
  62. }
  63. TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
  64. this.queue.Enqueue(tcs);
  65. return tcs.Task;
  66. }
  67. private async void RequestLock()
  68. {
  69. try
  70. {
  71. Session session = Game.Scene.GetComponent<NetInnerComponent>().Get(this.address);
  72. string serverAddress = Game.Scene.GetComponent<StartConfigComponent>().StartConfig.ServerIP;
  73. G2G_LockRequest request = new G2G_LockRequest { Id = this.Entity.Id, Address = serverAddress };
  74. await session.Call<G2G_LockResponse>(request);
  75. this.status = LockStatus.Locked;
  76. foreach (TaskCompletionSource<bool> taskCompletionSource in this.queue)
  77. {
  78. taskCompletionSource.SetResult(true);
  79. }
  80. this.queue.Clear();
  81. }
  82. catch (Exception e)
  83. {
  84. Log.Error($"获取锁失败: {this.address} {this.Entity.Id} {e}");
  85. }
  86. }
  87. public async Task Release()
  88. {
  89. --this.lockCount;
  90. if (this.lockCount != 0)
  91. {
  92. return;
  93. }
  94. this.status = LockStatus.LockedNot;
  95. Session session = Game.Scene.GetComponent<NetInnerComponent>().Get(this.address);
  96. G2G_LockReleaseRequest request = new G2G_LockReleaseRequest();
  97. await session.Call<G2G_LockReleaseResponse>(request);
  98. }
  99. }
  100. }