LockComponent.cs 2.5 KB

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