LockComponent.cs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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. if (this.status == LockStatus.Locked)
  62. {
  63. return Task.FromResult(true);
  64. }
  65. TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
  66. this.queue.Enqueue(tcs);
  67. return tcs.Task;
  68. }
  69. private async void RequestLock()
  70. {
  71. try
  72. {
  73. Session session = Game.Scene.GetComponent<NetInnerComponent>().Get(this.address);
  74. string serverAddress = Game.Scene.GetComponent<StartConfigComponent>().StartConfig.ServerIP;
  75. G2G_LockRequest request = new G2G_LockRequest { Id = this.Owner.Id, Address = serverAddress };
  76. await session.Call<G2G_LockRequest, G2G_LockResponse>(request);
  77. this.status = LockStatus.Locked;
  78. foreach (TaskCompletionSource<bool> taskCompletionSource in this.queue)
  79. {
  80. taskCompletionSource.SetResult(true);
  81. }
  82. this.queue.Clear();
  83. }
  84. catch (Exception e)
  85. {
  86. Log.Error($"获取锁失败: {this.address} {this.Owner.Id} {e}");
  87. }
  88. }
  89. public async Task Release()
  90. {
  91. --this.lockCount;
  92. if (this.lockCount != 0)
  93. {
  94. return;
  95. }
  96. this.status = LockStatus.LockedNot;
  97. Session session = Game.Scene.GetComponent<NetInnerComponent>().Get(this.address);
  98. G2G_LockReleaseRequest request = new G2G_LockReleaseRequest();
  99. await session.Call<G2G_LockReleaseRequest, G2G_LockReleaseResponse>(request);
  100. }
  101. }
  102. }