LockComponent.cs 2.6 KB

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