erlang's global lock
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

121 行
3.4 KiB

  1. #include "erl_nif.h"
  2. #include <atomic>
  3. using namespace std;
  4. const int LockSize = 2097152;
  5. atomic<uint64_t> LockSlot[LockSize];
  6. ERL_NIF_TERM atomTrue;
  7. ERL_NIF_TERM atomFalse;
  8. ERL_NIF_TERM atomUndefined;
  9. int nifLoad(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info){
  10. atomTrue = enif_make_atom(env, "true");
  11. atomFalse = enif_make_atom(env, "false");
  12. atomUndefined = enif_make_atom(env, "undefined");
  13. return 0;
  14. }
  15. inline bool lockOne(ErlNifEnv *env, ErlNifPid *ThePid, int KeyIx, uint64_t Val){
  16. uint64_t Expected = 0;
  17. if (LockSlot[KeyIx].compare_exchange_strong(Expected, Val)){
  18. return true;
  19. }else{
  20. ThePid->pid = (ERL_NIF_TERM)Expected;
  21. if (enif_is_process_alive(env, ThePid)){
  22. return false;
  23. }else{
  24. return LockSlot[KeyIx].compare_exchange_strong(Expected, Val);
  25. }
  26. }
  27. }
  28. ERL_NIF_TERM tryLock(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]){
  29. int KeyIx;
  30. enif_get_int(env, argv[0], &KeyIx);
  31. ErlNifPid ThePid;
  32. enif_self(env, &ThePid);
  33. uint64_t Val = (uint64_t)(ThePid.pid);
  34. return lockOne(env, &ThePid, KeyIx, Val) ? atomTrue : atomFalse;
  35. }
  36. ERL_NIF_TERM tryLocks(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]){
  37. ERL_NIF_TERM allList = argv[0];
  38. ERL_NIF_TERM head;
  39. ErlNifPid ThePid;
  40. enif_self(env, &ThePid);
  41. uint64_t Val = (uint64_t)(ThePid.pid);
  42. int KeyIx;
  43. int cnt = -1;
  44. while (enif_get_list_cell(env, allList, &head, &allList)){
  45. enif_get_int(env, head, &KeyIx);
  46. if(lockOne(env, &ThePid, KeyIx, Val)){
  47. cnt++;
  48. }else{
  49. allList = argv[0];
  50. for(int i = 0; i <= cnt; i++){
  51. enif_get_list_cell(env, allList, &head, &allList);
  52. enif_get_int(env, head, &KeyIx);
  53. LockSlot[KeyIx].store(0);
  54. }
  55. return atomFalse;
  56. }
  57. }
  58. return atomTrue;
  59. }
  60. ERL_NIF_TERM releaseLock(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]){
  61. int KeyIx;
  62. enif_get_int(env, argv[0], &KeyIx);
  63. ErlNifPid ThePid;
  64. enif_self(env, &ThePid);
  65. uint64_t Expected = (uint64_t)(ThePid.pid);
  66. return LockSlot[KeyIx].compare_exchange_strong(Expected, 0) ? atomTrue : atomFalse;
  67. }
  68. ERL_NIF_TERM releaseLocks(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]){
  69. ERL_NIF_TERM allList = argv[0];
  70. ERL_NIF_TERM head;
  71. ErlNifPid ThePid;
  72. enif_self(env, &ThePid);
  73. uint64_t Expected = (uint64_t)(ThePid.pid);
  74. uint64_t RExpected;
  75. int KeyIx;
  76. int isAllOk = 1;
  77. while (enif_get_list_cell(env, allList, &head, &allList)){
  78. enif_get_int(env, head, &KeyIx);
  79. RExpected = Expected;
  80. if (!LockSlot[KeyIx].compare_exchange_strong(RExpected, 0)){
  81. isAllOk = 0;
  82. }
  83. }
  84. return isAllOk > 0 ? atomTrue : atomFalse;
  85. }
  86. ERL_NIF_TERM getLockPid(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]){
  87. int KeyIx;
  88. enif_get_int(env, argv[0], &KeyIx);
  89. ErlNifPid ThePid;
  90. uint64_t Var = LockSlot[KeyIx].load();
  91. if (Var > 0){
  92. ThePid.pid = (ERL_NIF_TERM)Var;
  93. return enif_make_pid(env, &ThePid);
  94. }else{
  95. return atomUndefined;
  96. }
  97. }
  98. static ErlNifFunc nifFuncs[] = {
  99. {"tryLock", 1, tryLock},
  100. {"tryLocks", 1, tryLocks},
  101. {"releaseLock", 1, releaseLock},
  102. {"releaseLocks", 1, releaseLocks},
  103. {"getLockPid", 1, getLockPid}
  104. };
  105. ERL_NIF_INIT(eNifLock, nifFuncs, &nifLoad, NULL, NULL, NULL)