fork download
  1. #include <string>
  2. #include <stdexcept>
  3. #include <iostream>
  4. #include <cassert>
  5. #include <thread>
  6. #include <chrono>
  7.  
  8. #include <cstdlib>
  9. #include <unistd.h>
  10. #include <sys/file.h>
  11. #include <sys/stat.h>
  12.  
  13. struct FileLock
  14. {
  15. std::string _path;
  16.  
  17. FileLock(const std::string& p, bool acq = false)
  18. : _path(p)
  19. {
  20. if (acq)
  21. {
  22. bool r = acquire();
  23. if (!r) throw std::runtime_error("FileLock::acquire failed");
  24. }
  25. }
  26.  
  27. ~FileLock()
  28. {
  29. bool r = release();
  30. if (!r) std::cerr << "FileLock::release failed";
  31. }
  32.  
  33. const char* path() const {return _path.c_str();}
  34.  
  35. // #############################################################################
  36.  
  37. #define CHECK_OK_(v, pred) \
  38.   { \
  39.   bool res = (pred); \
  40.   if (!res) std::cerr<< ("FileLock: (" #pred ") = false"); \
  41.   v &= res; \
  42.   }
  43.  
  44. bool acquire()
  45. {
  46. bool ok = true;
  47. int r;
  48.  
  49. // auto fp = std::fopen(_path.c_str(), "w");
  50. // if (!fp)
  51. // return false;
  52.  
  53. // int fd = ::fileno(fp);
  54.  
  55. auto m = umask(0);
  56. int fd = ::open(_path.c_str(), O_RDWR | O_CREAT, 0666);
  57. umask(m);
  58.  
  59. CHECK_OK_(ok, fd != -1);
  60. if (ok)
  61. {
  62. r = ::flock(fd, LOCK_EX | LOCK_NB);
  63. CHECK_OK_(ok, r != -1);
  64. if (ok)
  65. { // write pid
  66. pid_t pid = getpid();
  67. auto pstr = std::to_string(pid);
  68. auto wr = ::write(fd, pstr.c_str(), pstr.size());
  69. CHECK_OK_(ok, wr == pstr.size());
  70. }
  71. }
  72.  
  73. // CHECK_OK_(ok, std::fclose(fp) == 0);
  74. CHECK_OK_(ok, ::close(fd) == 0);
  75.  
  76. return ok;
  77. }
  78.  
  79. // #############################################################################
  80.  
  81. bool release()
  82. {
  83. bool ok = true;
  84.  
  85. // auto fp = std::fopen(_path.c_str(), "r");
  86. // if (!fp)
  87. // return false;
  88.  
  89. // int fd = ::fileno(fp);
  90.  
  91. int fd = ::open(_path.c_str(), O_RDONLY);
  92. CHECK_OK_(ok, fd != -1);
  93. if (ok)
  94. {
  95. int r = ::flock(fd, LOCK_UN | LOCK_NB);
  96. CHECK_OK_(ok, r != -1);
  97. }
  98.  
  99. // pid should == getpid()
  100.  
  101. // CHECK_OK_(ok, std::fclose(fp) == 0);
  102. CHECK_OK_(ok, ::close(fd) == 0);
  103.  
  104. // necessary?
  105. CHECK_OK_(ok, std::remove(_path.c_str()) != -1);
  106.  
  107. return ok;
  108. }
  109.  
  110. #undef CHECK_OK_
  111.  
  112. };
  113.  
  114. int main(int ac, const char* av[])
  115. {
  116. assert((ac >= 2) && "usage: prog file_name");
  117.  
  118. FileLock fl(av[1], true);
  119.  
  120. while (1)
  121. {
  122. std::this_thread::sleep_for(std::chrono::seconds{1});
  123. std::cout << "waiting... \n";
  124. }
  125. }
  126.  
Runtime error #stdin #stdout #stderr 0s 3432KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
prog: prog.cpp:116: int main(int, const char**): Assertion `(ac >= 2) && "usage: prog file_name"' failed.