Marine Library  1.0
C++ library for Linux Networking Development
semaphore.hh
1 #ifndef DOZERG_SEMAPHORE_H_20090318
2 #define DOZERG_SEMAPHORE_H_20090318
3 
4 /*
5  对POSIX信号量进行简单的封装
6  方便使用,隐藏底层实现,便于移植
7  CSemaphore POSIX有名信号量
8  CUnnamedSemaphore POSIX无名信号量
9  CXsiSemaphoreSet XSI信号量集
10 //*/
11 
12 #include <sys/types.h>
13 #include <sys/ipc.h>
14 #include <sys/sem.h>
15 #include <fcntl.h>
16 #include <semaphore.h>
17 #include <errno.h>
18 #include <cassert>
19 #include <vector>
20 #include "tools/time.hh"
21 
22 NS_SERVER_BEGIN
23 
25 {
26  CUnnamedSemaphore(const CUnnamedSemaphore &); //disable copy and assignment
27  CUnnamedSemaphore & operator =(const CUnnamedSemaphore &);
28 public:
30  //init unnamed semaphore
31  //init_val: init value of Semaphore
32  //pshared: shared in process(true) or threads(false)
33  //注意:
34  //如果pshared=true,那么对象应该位于shm中,否则无法实现进程间共享;
35  bool init(unsigned int init_val, bool pshared){
36  return (0 == ::sem_init(&sem_, pshared, init_val));
37  }
38  //destroy unnamed semaphore
39  //注意:
40  //本函数可由任何进程/线程调用,但需要与init调用匹配,否则可能造成不确定结果 bool destroy(){ return (0 == ::sem_destroy(&sem_)); } //unlock semaphore bool post(){return (0 == ::sem_post(&sem_));} //lock semaphore bool wait(){return (0 == ::sem_wait(&sem_));} //try to lock semaphore bool tryWait(){return (0 == ::sem_trywait(&sem_));} #ifdef __API_HAS_SEM_TIMEWAIT //在指定的timeMs毫秒内如果不能获取信号量,返回false bool timeWait(uint32_t timeMs){ struct timespec ts; return (tools::GetAbsTimespec(timeMs, &ts) && 0 == ::sem_timedwait(&sem_, &ts)); } #endif //获取信号量的当前值;返回-1表示获取失败 int getVal() const{ int ret = -1; if(0 == ::sem_getvalue(&sem_, &ret) && ret < 0) ret = 0; return ret; } private: mutable sem_t sem_; }; class CSemaphore { CSemaphore(const CSemaphore &); //disable copy and assignment CSemaphore & operator =(const CSemaphore &); static const int kModeDefault = S_IRUSR | S_IWUSR;// | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; public: //remove named semaphore //TODO: unit test static bool Unlink(const char * name){ assert(name); return (0 == sem_unlink(name)); } //init named semaphore //name: file name of Semaphore //init_val: init value of Semaphore //oflag: for sem_open() //mode: for sem_open() explicit CSemaphore(const char * name , unsigned int init_val = 0 , int oflag = O_CREAT , mode_t mode = kModeDefault) : semp_(NULL) { //注意: //如果遇到sem_open()失败,而错误为"No such file or directory"失败,原因可能是name里有目录 //因为sem_open试图创建/dev/shm/sem.name文件,如果name里有目录,则会因为目录不存在而失败 sem_t * s = sem_open(name, oflag, mode, init_val); if(SEM_FAILED != s) semp_ = s; } ~CSemaphore(){ if(semp_) sem_close(semp_); semp_ = NULL; } bool valid() const{return (semp_ != NULL);} //unlock semaphore(++sem_val) bool post(){return (valid() && 0 == sem_post(semp_));} //lock semaphore(--sem_val) bool wait(){return (valid() && 0 == sem_wait(semp_));} //try to lock semaphore bool tryWait(){return (valid() && 0 == sem_trywait(semp_));} #ifdef __API_HAS_SEM_TIMEWAIT //在指定的timeMs毫秒内如果不能获取信号量,返回false bool timeWait(uint32_t timeMs){ struct timespec ts; return (valid() && tools::GetAbsTimespec(timeMs, &ts) && 0 == sem_timedwait(semp_, &ts)); } #endif //获取信号量的当前值;返回-1表示获取失败 int getVal() const{ int ret = -1; if(valid() && 0 == sem_getvalue(semp_, &ret) && ret < 0) ret = 0; return ret; } private: sem_t * semp_; }; class CXsiSemaphoreSet { union semun { int val; // Value for SETVAL struct semid_ds *buf; // Buffer for IPC_STAT, IPC_SET unsigned short *array; // Array for GETALL, SETALL struct seminfo *__buf; // Buffer for IPC_INFO (Linux-specific) }; public: static const int kFlagDefault = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; //generate an operation static sembuf GenOp(int index, int op, bool wait, bool undo){ sembuf sb; sb.sem_num = index; sb.sem_op = op; sb.sem_flg = 0; if(!wait) sb.sem_flg |= IPC_NOWAIT; if(undo) sb.sem_flg |= SEM_UNDO; return sb; } CXsiSemaphoreSet():semid_(-1){} //init semaphore set //key: key for semaphore set //nsems: // 0 ignored // other number of semaphores in set //semflg: access flags for semaphores in set explicit CXsiSemaphoreSet(key_t key, int nsems = 0, int semflg = kFlagDefault) : semid_(-1) { init(key, nsems, semflg); } //pathname: file pathname for semaphore set, must be existing and accessible //project: project identifier for semaphore set CXsiSemaphoreSet(const char * pathname, int project, int nsems = 0, int semflg = kFlagDefault) : semid_(-1) { init(pathname, project, nsems, semflg); } bool init(key_t key, int nsems, int semflg){ if(valid()) return false; semid_ = ::semget(key, nsems, semflg); return valid(); } bool init(const char * pathname, int project, int nsems, int semflg){ if(valid()) return false; key_t key = ::ftok(pathname, project); if(-1 == key) return false; return init(key, nsems, semflg); } bool valid() const{return (semid_ >= 0);} //get number of semaphores in set size_t size() const{ if(!valid()) return 0; struct semid_ds sem; union semun arg; arg.buf = &sem; if(0 > ::semctl(semid_, 0, IPC_STAT, arg)) return 0; return sem.sem_nsems; } //get all semvals in semaphore set bool getAll(std::vector<unsigned short> & results) const{ if(!valid()) return false; const size_t sz = size(); if(!sz) return false; results.resize(sz); union semun arg; arg.array = &results[0]; return (0 == ::semctl(semid_, 0, GETALL, arg)); } //set semval of all semaphores in set bool setAll(const std::vector<unsigned short> & values){ if(!valid()) return false; const size_t sz = size(); if(!sz || values.size() < sz) return false; union semun arg; arg.array = const_cast<unsigned short *>(&values[0]); return (0 == ::semctl(semid_, 0, SETALL, arg)); } //set semval of one semaphone in set bool setVal(int index, int val){ if(!valid()) return false; union semun arg; arg.val = val; return (0 == ::semctl(semid_, index, SETVAL, arg)); } //get semval of one semaphone in set //return: // <0 failed // others semval int getVal(int index) const{ if(!valid()) return -1; return ::semctl(semid_, index, GETVAL); } //apply operation(s) on semaphore(s) in set //index: index of semaphore in set //op: increment or decrement for semval; if ZERO, then wait for semval=0 //wait: wait or not if operaton suspended //undo: undo or not when process exit bool apply(int index, int op, bool wait, bool undo){ if(!valid()) return false; sembuf sb(GenOp(index, op, wait, undo)); return (0 == ::semop(semid_, &sb, 1)); } //ops: operations array bool apply(const std::vector<sembuf> & ops){ if(!valid()) return false; if(ops.empty()) return true; return (0 == ::semop(semid_, const_cast<sembuf *>(&ops[0]), ops.size())); } #ifdef __API_HAS_SEMTIMEDOP //timeMs: if suspended, wait for timeMs milli-seconds bool timeApply(int index, int op, bool wait, bool undo, uint32_t timeMs){ if(!valid()) return false; sembuf sb(GenOp(index, op, wait, undo)); struct timespec ts; tools::GetRelativeTimespec(timeMs, &ts); return (0 == ::semtimedop(semid_, &sb, 1, &ts)); } bool timeApply(const std::vector<sembuf> & ops, uint32_t timeMs){ if(!valid()) return false; if(ops.empty()) return true; struct timespec ts; tools::GetRelativeTimespec(timeMs, &ts); return (0 == ::semtimedop(semid_, const_cast<sembuf *>(&ops[0]), ops.size(), &ts)); } #endif //destroy semaphore set from system void destroy(){ if(valid()){ ::semctl(semid_, 0, IPC_RMID); semid_ = -1; } } private: int semid_; }; NS_SERVER_END #endif
41  bool destroy(){
42  return (0 == ::sem_destroy(&sem_));
43  }
44  //unlock semaphore
45  bool post(){return (0 == ::sem_post(&sem_));}
46  //lock semaphore
47  bool wait(){return (0 == ::sem_wait(&sem_));}
48  //try to lock semaphore
49  bool tryWait(){return (0 == ::sem_trywait(&sem_));}
50 #ifdef __API_HAS_SEM_TIMEWAIT
51  //在指定的timeMs毫秒内如果不能获取信号量,返回false
52  bool timeWait(uint32_t timeMs){
53  struct timespec ts;
54  return (tools::GetAbsTimespec(timeMs, &ts)
55  && 0 == ::sem_timedwait(&sem_, &ts));
56  }
57 #endif
58  //获取信号量的当前值;返回-1表示获取失败 int getVal() const{ int ret = -1; if(0 == ::sem_getvalue(&sem_, &ret) && ret < 0) ret = 0; return ret; } private: mutable sem_t sem_; }; class CSemaphore { CSemaphore(const CSemaphore &); //disable copy and assignment CSemaphore & operator =(const CSemaphore &); static const int kModeDefault = S_IRUSR | S_IWUSR;// | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; public: //remove named semaphore //TODO: unit test static bool Unlink(const char * name){ assert(name); return (0 == sem_unlink(name)); } //init named semaphore //name: file name of Semaphore //init_val: init value of Semaphore //oflag: for sem_open() //mode: for sem_open() explicit CSemaphore(const char * name , unsigned int init_val = 0 , int oflag = O_CREAT , mode_t mode = kModeDefault) : semp_(NULL) { //注意: //如果遇到sem_open()失败,而错误为"No such file or directory"失败,原因可能是name里有目录 //因为sem_open试图创建/dev/shm/sem.name文件,如果name里有目录,则会因为目录不存在而失败 sem_t * s = sem_open(name, oflag, mode, init_val); if(SEM_FAILED != s) semp_ = s; } ~CSemaphore(){ if(semp_) sem_close(semp_); semp_ = NULL; } bool valid() const{return (semp_ != NULL);} //unlock semaphore(++sem_val) bool post(){return (valid() && 0 == sem_post(semp_));} //lock semaphore(--sem_val) bool wait(){return (valid() && 0 == sem_wait(semp_));} //try to lock semaphore bool tryWait(){return (valid() && 0 == sem_trywait(semp_));} #ifdef __API_HAS_SEM_TIMEWAIT //在指定的timeMs毫秒内如果不能获取信号量,返回false bool timeWait(uint32_t timeMs){ struct timespec ts; return (valid() && tools::GetAbsTimespec(timeMs, &ts) && 0 == sem_timedwait(semp_, &ts)); } #endif //获取信号量的当前值;返回-1表示获取失败 int getVal() const{ int ret = -1; if(valid() && 0 == sem_getvalue(semp_, &ret) && ret < 0) ret = 0; return ret; } private: sem_t * semp_; }; class CXsiSemaphoreSet { union semun { int val; // Value for SETVAL struct semid_ds *buf; // Buffer for IPC_STAT, IPC_SET unsigned short *array; // Array for GETALL, SETALL struct seminfo *__buf; // Buffer for IPC_INFO (Linux-specific) }; public: static const int kFlagDefault = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; //generate an operation static sembuf GenOp(int index, int op, bool wait, bool undo){ sembuf sb; sb.sem_num = index; sb.sem_op = op; sb.sem_flg = 0; if(!wait) sb.sem_flg |= IPC_NOWAIT; if(undo) sb.sem_flg |= SEM_UNDO; return sb; } CXsiSemaphoreSet():semid_(-1){} //init semaphore set //key: key for semaphore set //nsems: // 0 ignored // other number of semaphores in set //semflg: access flags for semaphores in set explicit CXsiSemaphoreSet(key_t key, int nsems = 0, int semflg = kFlagDefault) : semid_(-1) { init(key, nsems, semflg); } //pathname: file pathname for semaphore set, must be existing and accessible //project: project identifier for semaphore set CXsiSemaphoreSet(const char * pathname, int project, int nsems = 0, int semflg = kFlagDefault) : semid_(-1) { init(pathname, project, nsems, semflg); } bool init(key_t key, int nsems, int semflg){ if(valid()) return false; semid_ = ::semget(key, nsems, semflg); return valid(); } bool init(const char * pathname, int project, int nsems, int semflg){ if(valid()) return false; key_t key = ::ftok(pathname, project); if(-1 == key) return false; return init(key, nsems, semflg); } bool valid() const{return (semid_ >= 0);} //get number of semaphores in set size_t size() const{ if(!valid()) return 0; struct semid_ds sem; union semun arg; arg.buf = &sem; if(0 > ::semctl(semid_, 0, IPC_STAT, arg)) return 0; return sem.sem_nsems; } //get all semvals in semaphore set bool getAll(std::vector<unsigned short> & results) const{ if(!valid()) return false; const size_t sz = size(); if(!sz) return false; results.resize(sz); union semun arg; arg.array = &results[0]; return (0 == ::semctl(semid_, 0, GETALL, arg)); } //set semval of all semaphores in set bool setAll(const std::vector<unsigned short> & values){ if(!valid()) return false; const size_t sz = size(); if(!sz || values.size() < sz) return false; union semun arg; arg.array = const_cast<unsigned short *>(&values[0]); return (0 == ::semctl(semid_, 0, SETALL, arg)); } //set semval of one semaphone in set bool setVal(int index, int val){ if(!valid()) return false; union semun arg; arg.val = val; return (0 == ::semctl(semid_, index, SETVAL, arg)); } //get semval of one semaphone in set //return: // <0 failed // others semval int getVal(int index) const{ if(!valid()) return -1; return ::semctl(semid_, index, GETVAL); } //apply operation(s) on semaphore(s) in set //index: index of semaphore in set //op: increment or decrement for semval; if ZERO, then wait for semval=0 //wait: wait or not if operaton suspended //undo: undo or not when process exit bool apply(int index, int op, bool wait, bool undo){ if(!valid()) return false; sembuf sb(GenOp(index, op, wait, undo)); return (0 == ::semop(semid_, &sb, 1)); } //ops: operations array bool apply(const std::vector<sembuf> & ops){ if(!valid()) return false; if(ops.empty()) return true; return (0 == ::semop(semid_, const_cast<sembuf *>(&ops[0]), ops.size())); } #ifdef __API_HAS_SEMTIMEDOP //timeMs: if suspended, wait for timeMs milli-seconds bool timeApply(int index, int op, bool wait, bool undo, uint32_t timeMs){ if(!valid()) return false; sembuf sb(GenOp(index, op, wait, undo)); struct timespec ts; tools::GetRelativeTimespec(timeMs, &ts); return (0 == ::semtimedop(semid_, &sb, 1, &ts)); } bool timeApply(const std::vector<sembuf> & ops, uint32_t timeMs){ if(!valid()) return false; if(ops.empty()) return true; struct timespec ts; tools::GetRelativeTimespec(timeMs, &ts); return (0 == ::semtimedop(semid_, const_cast<sembuf *>(&ops[0]), ops.size(), &ts)); } #endif //destroy semaphore set from system void destroy(){ if(valid()){ ::semctl(semid_, 0, IPC_RMID); semid_ = -1; } } private: int semid_; }; NS_SERVER_END #endif
59  int getVal() const{
60  int ret = -1;
61  if(0 == ::sem_getvalue(&sem_, &ret) && ret < 0)
62  ret = 0;
63  return ret;
64  }
65 private:
66  mutable sem_t sem_;
67 };
68 
70 {
71  CSemaphore(const CSemaphore &); //disable copy and assignment
72  CSemaphore & operator =(const CSemaphore &);
73  static const int kModeDefault = S_IRUSR | S_IWUSR;// | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
74 public:
75  //remove named semaphore
76  //TODO: unit test
77  static bool Unlink(const char * name){
78  assert(name);
79  return (0 == sem_unlink(name));
80  }
81  //init named semaphore
82  //name: file name of Semaphore
83  //init_val: init value of Semaphore
84  //oflag: for sem_open()
85  //mode: for sem_open()
86  explicit CSemaphore(const char * name
87  , unsigned int init_val = 0
88  , int oflag = O_CREAT
89  , mode_t mode = kModeDefault)
90  : semp_(NULL)
91  {
92  //注意:
93  //如果遇到sem_open()失败,而错误为"No such file or directory"失败,原因可能是name里有目录
94  //因为sem_open试图创建/dev/shm/sem.name文件,如果name里有目录,则会因为目录不存在而失败 sem_t * s = sem_open(name, oflag, mode, init_val); if(SEM_FAILED != s) semp_ = s; } ~CSemaphore(){ if(semp_) sem_close(semp_); semp_ = NULL; } bool valid() const{return (semp_ != NULL);} //unlock semaphore(++sem_val) bool post(){return (valid() && 0 == sem_post(semp_));} //lock semaphore(--sem_val) bool wait(){return (valid() && 0 == sem_wait(semp_));} //try to lock semaphore bool tryWait(){return (valid() && 0 == sem_trywait(semp_));} #ifdef __API_HAS_SEM_TIMEWAIT //在指定的timeMs毫秒内如果不能获取信号量,返回false bool timeWait(uint32_t timeMs){ struct timespec ts; return (valid() && tools::GetAbsTimespec(timeMs, &ts) && 0 == sem_timedwait(semp_, &ts)); } #endif //获取信号量的当前值;返回-1表示获取失败 int getVal() const{ int ret = -1; if(valid() && 0 == sem_getvalue(semp_, &ret) && ret < 0) ret = 0; return ret; } private: sem_t * semp_; }; class CXsiSemaphoreSet { union semun { int val; // Value for SETVAL struct semid_ds *buf; // Buffer for IPC_STAT, IPC_SET unsigned short *array; // Array for GETALL, SETALL struct seminfo *__buf; // Buffer for IPC_INFO (Linux-specific) }; public: static const int kFlagDefault = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; //generate an operation static sembuf GenOp(int index, int op, bool wait, bool undo){ sembuf sb; sb.sem_num = index; sb.sem_op = op; sb.sem_flg = 0; if(!wait) sb.sem_flg |= IPC_NOWAIT; if(undo) sb.sem_flg |= SEM_UNDO; return sb; } CXsiSemaphoreSet():semid_(-1){} //init semaphore set //key: key for semaphore set //nsems: // 0 ignored // other number of semaphores in set //semflg: access flags for semaphores in set explicit CXsiSemaphoreSet(key_t key, int nsems = 0, int semflg = kFlagDefault) : semid_(-1) { init(key, nsems, semflg); } //pathname: file pathname for semaphore set, must be existing and accessible //project: project identifier for semaphore set CXsiSemaphoreSet(const char * pathname, int project, int nsems = 0, int semflg = kFlagDefault) : semid_(-1) { init(pathname, project, nsems, semflg); } bool init(key_t key, int nsems, int semflg){ if(valid()) return false; semid_ = ::semget(key, nsems, semflg); return valid(); } bool init(const char * pathname, int project, int nsems, int semflg){ if(valid()) return false; key_t key = ::ftok(pathname, project); if(-1 == key) return false; return init(key, nsems, semflg); } bool valid() const{return (semid_ >= 0);} //get number of semaphores in set size_t size() const{ if(!valid()) return 0; struct semid_ds sem; union semun arg; arg.buf = &sem; if(0 > ::semctl(semid_, 0, IPC_STAT, arg)) return 0; return sem.sem_nsems; } //get all semvals in semaphore set bool getAll(std::vector<unsigned short> & results) const{ if(!valid()) return false; const size_t sz = size(); if(!sz) return false; results.resize(sz); union semun arg; arg.array = &results[0]; return (0 == ::semctl(semid_, 0, GETALL, arg)); } //set semval of all semaphores in set bool setAll(const std::vector<unsigned short> & values){ if(!valid()) return false; const size_t sz = size(); if(!sz || values.size() < sz) return false; union semun arg; arg.array = const_cast<unsigned short *>(&values[0]); return (0 == ::semctl(semid_, 0, SETALL, arg)); } //set semval of one semaphone in set bool setVal(int index, int val){ if(!valid()) return false; union semun arg; arg.val = val; return (0 == ::semctl(semid_, index, SETVAL, arg)); } //get semval of one semaphone in set //return: // <0 failed // others semval int getVal(int index) const{ if(!valid()) return -1; return ::semctl(semid_, index, GETVAL); } //apply operation(s) on semaphore(s) in set //index: index of semaphore in set //op: increment or decrement for semval; if ZERO, then wait for semval=0 //wait: wait or not if operaton suspended //undo: undo or not when process exit bool apply(int index, int op, bool wait, bool undo){ if(!valid()) return false; sembuf sb(GenOp(index, op, wait, undo)); return (0 == ::semop(semid_, &sb, 1)); } //ops: operations array bool apply(const std::vector<sembuf> & ops){ if(!valid()) return false; if(ops.empty()) return true; return (0 == ::semop(semid_, const_cast<sembuf *>(&ops[0]), ops.size())); } #ifdef __API_HAS_SEMTIMEDOP //timeMs: if suspended, wait for timeMs milli-seconds bool timeApply(int index, int op, bool wait, bool undo, uint32_t timeMs){ if(!valid()) return false; sembuf sb(GenOp(index, op, wait, undo)); struct timespec ts; tools::GetRelativeTimespec(timeMs, &ts); return (0 == ::semtimedop(semid_, &sb, 1, &ts)); } bool timeApply(const std::vector<sembuf> & ops, uint32_t timeMs){ if(!valid()) return false; if(ops.empty()) return true; struct timespec ts; tools::GetRelativeTimespec(timeMs, &ts); return (0 == ::semtimedop(semid_, const_cast<sembuf *>(&ops[0]), ops.size(), &ts)); } #endif //destroy semaphore set from system void destroy(){ if(valid()){ ::semctl(semid_, 0, IPC_RMID); semid_ = -1; } } private: int semid_; }; NS_SERVER_END #endif
95  sem_t * s = sem_open(name, oflag, mode, init_val);
96  if(SEM_FAILED != s)
97  semp_ = s;
98  }
99  ~CSemaphore(){
100  if(semp_)
101  sem_close(semp_);
102  semp_ = NULL;
103  }
104  bool valid() const{return (semp_ != NULL);}
105  //unlock semaphore(++sem_val)
106  bool post(){return (valid() && 0 == sem_post(semp_));}
107  //lock semaphore(--sem_val)
108  bool wait(){return (valid() && 0 == sem_wait(semp_));}
109  //try to lock semaphore
110  bool tryWait(){return (valid() && 0 == sem_trywait(semp_));}
111 #ifdef __API_HAS_SEM_TIMEWAIT
112  //在指定的timeMs毫秒内如果不能获取信号量,返回false
113  bool timeWait(uint32_t timeMs){
114  struct timespec ts;
115  return (valid()
116  && tools::GetAbsTimespec(timeMs, &ts)
117  && 0 == sem_timedwait(semp_, &ts));
118  }
119 #endif
120  //获取信号量的当前值;返回-1表示获取失败 int getVal() const{ int ret = -1; if(valid() && 0 == sem_getvalue(semp_, &ret) && ret < 0) ret = 0; return ret; } private: sem_t * semp_; }; class CXsiSemaphoreSet { union semun { int val; // Value for SETVAL struct semid_ds *buf; // Buffer for IPC_STAT, IPC_SET unsigned short *array; // Array for GETALL, SETALL struct seminfo *__buf; // Buffer for IPC_INFO (Linux-specific) }; public: static const int kFlagDefault = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; //generate an operation static sembuf GenOp(int index, int op, bool wait, bool undo){ sembuf sb; sb.sem_num = index; sb.sem_op = op; sb.sem_flg = 0; if(!wait) sb.sem_flg |= IPC_NOWAIT; if(undo) sb.sem_flg |= SEM_UNDO; return sb; } CXsiSemaphoreSet():semid_(-1){} //init semaphore set //key: key for semaphore set //nsems: // 0 ignored // other number of semaphores in set //semflg: access flags for semaphores in set explicit CXsiSemaphoreSet(key_t key, int nsems = 0, int semflg = kFlagDefault) : semid_(-1) { init(key, nsems, semflg); } //pathname: file pathname for semaphore set, must be existing and accessible //project: project identifier for semaphore set CXsiSemaphoreSet(const char * pathname, int project, int nsems = 0, int semflg = kFlagDefault) : semid_(-1) { init(pathname, project, nsems, semflg); } bool init(key_t key, int nsems, int semflg){ if(valid()) return false; semid_ = ::semget(key, nsems, semflg); return valid(); } bool init(const char * pathname, int project, int nsems, int semflg){ if(valid()) return false; key_t key = ::ftok(pathname, project); if(-1 == key) return false; return init(key, nsems, semflg); } bool valid() const{return (semid_ >= 0);} //get number of semaphores in set size_t size() const{ if(!valid()) return 0; struct semid_ds sem; union semun arg; arg.buf = &sem; if(0 > ::semctl(semid_, 0, IPC_STAT, arg)) return 0; return sem.sem_nsems; } //get all semvals in semaphore set bool getAll(std::vector<unsigned short> & results) const{ if(!valid()) return false; const size_t sz = size(); if(!sz) return false; results.resize(sz); union semun arg; arg.array = &results[0]; return (0 == ::semctl(semid_, 0, GETALL, arg)); } //set semval of all semaphores in set bool setAll(const std::vector<unsigned short> & values){ if(!valid()) return false; const size_t sz = size(); if(!sz || values.size() < sz) return false; union semun arg; arg.array = const_cast<unsigned short *>(&values[0]); return (0 == ::semctl(semid_, 0, SETALL, arg)); } //set semval of one semaphone in set bool setVal(int index, int val){ if(!valid()) return false; union semun arg; arg.val = val; return (0 == ::semctl(semid_, index, SETVAL, arg)); } //get semval of one semaphone in set //return: // <0 failed // others semval int getVal(int index) const{ if(!valid()) return -1; return ::semctl(semid_, index, GETVAL); } //apply operation(s) on semaphore(s) in set //index: index of semaphore in set //op: increment or decrement for semval; if ZERO, then wait for semval=0 //wait: wait or not if operaton suspended //undo: undo or not when process exit bool apply(int index, int op, bool wait, bool undo){ if(!valid()) return false; sembuf sb(GenOp(index, op, wait, undo)); return (0 == ::semop(semid_, &sb, 1)); } //ops: operations array bool apply(const std::vector<sembuf> & ops){ if(!valid()) return false; if(ops.empty()) return true; return (0 == ::semop(semid_, const_cast<sembuf *>(&ops[0]), ops.size())); } #ifdef __API_HAS_SEMTIMEDOP //timeMs: if suspended, wait for timeMs milli-seconds bool timeApply(int index, int op, bool wait, bool undo, uint32_t timeMs){ if(!valid()) return false; sembuf sb(GenOp(index, op, wait, undo)); struct timespec ts; tools::GetRelativeTimespec(timeMs, &ts); return (0 == ::semtimedop(semid_, &sb, 1, &ts)); } bool timeApply(const std::vector<sembuf> & ops, uint32_t timeMs){ if(!valid()) return false; if(ops.empty()) return true; struct timespec ts; tools::GetRelativeTimespec(timeMs, &ts); return (0 == ::semtimedop(semid_, const_cast<sembuf *>(&ops[0]), ops.size(), &ts)); } #endif //destroy semaphore set from system void destroy(){ if(valid()){ ::semctl(semid_, 0, IPC_RMID); semid_ = -1; } } private: int semid_; }; NS_SERVER_END #endif
121  int getVal() const{
122  int ret = -1;
123  if(valid() && 0 == sem_getvalue(semp_, &ret) && ret < 0)
124  ret = 0;
125  return ret;
126  }
127 private:
128  sem_t * semp_;
129 };
130 
132 {
133  union semun {
134  int val; // Value for SETVAL
135  struct semid_ds *buf; // Buffer for IPC_STAT, IPC_SET
136  unsigned short *array; // Array for GETALL, SETALL
137  struct seminfo *__buf; // Buffer for IPC_INFO (Linux-specific)
138  };
139 public:
140  static const int kFlagDefault = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
141  //generate an operation
142  static sembuf GenOp(int index, int op, bool wait, bool undo){
143  sembuf sb;
144  sb.sem_num = index;
145  sb.sem_op = op;
146  sb.sem_flg = 0;
147  if(!wait)
148  sb.sem_flg |= IPC_NOWAIT;
149  if(undo)
150  sb.sem_flg |= SEM_UNDO;
151  return sb;
152  }
153  CXsiSemaphoreSet():semid_(-1){}
154  //init semaphore set
155  //key: key for semaphore set
156  //nsems:
157  // 0 ignored
158  // other number of semaphores in set
159  //semflg: access flags for semaphores in set
160  explicit CXsiSemaphoreSet(key_t key, int nsems = 0, int semflg = kFlagDefault)
161  : semid_(-1)
162  {
163  init(key, nsems, semflg);
164  }
165  //pathname: file pathname for semaphore set, must be existing and accessible
166  //project: project identifier for semaphore set
167  CXsiSemaphoreSet(const char * pathname, int project, int nsems = 0, int semflg = kFlagDefault)
168  : semid_(-1)
169  {
170  init(pathname, project, nsems, semflg);
171  }
172  bool init(key_t key, int nsems, int semflg){
173  if(valid())
174  return false;
175  semid_ = ::semget(key, nsems, semflg);
176  return valid();
177  }
178  bool init(const char * pathname, int project, int nsems, int semflg){
179  if(valid())
180  return false;
181  key_t key = ::ftok(pathname, project);
182  if(-1 == key)
183  return false;
184  return init(key, nsems, semflg);
185  }
186  bool valid() const{return (semid_ >= 0);}
187  //get number of semaphores in set
188  size_t size() const{
189  if(!valid())
190  return 0;
191  struct semid_ds sem;
192  union semun arg;
193  arg.buf = &sem;
194  if(0 > ::semctl(semid_, 0, IPC_STAT, arg))
195  return 0;
196  return sem.sem_nsems;
197  }
198  //get all semvals in semaphore set
199  bool getAll(std::vector<unsigned short> & results) const{
200  if(!valid())
201  return false;
202  const size_t sz = size();
203  if(!sz)
204  return false;
205  results.resize(sz);
206  union semun arg;
207  arg.array = &results[0];
208  return (0 == ::semctl(semid_, 0, GETALL, arg));
209  }
210  //set semval of all semaphores in set
211  bool setAll(const std::vector<unsigned short> & values){
212  if(!valid())
213  return false;
214  const size_t sz = size();
215  if(!sz || values.size() < sz)
216  return false;
217  union semun arg;
218  arg.array = const_cast<unsigned short *>(&values[0]);
219  return (0 == ::semctl(semid_, 0, SETALL, arg));
220  }
221  //set semval of one semaphone in set
222  bool setVal(int index, int val){
223  if(!valid())
224  return false;
225  union semun arg;
226  arg.val = val;
227  return (0 == ::semctl(semid_, index, SETVAL, arg));
228  }
229  //get semval of one semaphone in set
230  //return:
231  // <0 failed
232  // others semval
233  int getVal(int index) const{
234  if(!valid())
235  return -1;
236  return ::semctl(semid_, index, GETVAL);
237  }
238  //apply operation(s) on semaphore(s) in set
239  //index: index of semaphore in set
240  //op: increment or decrement for semval; if ZERO, then wait for semval=0
241  //wait: wait or not if operaton suspended
242  //undo: undo or not when process exit
243  bool apply(int index, int op, bool wait, bool undo){
244  if(!valid())
245  return false;
246  sembuf sb(GenOp(index, op, wait, undo));
247  return (0 == ::semop(semid_, &sb, 1));
248  }
249  //ops: operations array
250  bool apply(const std::vector<sembuf> & ops){
251  if(!valid())
252  return false;
253  if(ops.empty())
254  return true;
255  return (0 == ::semop(semid_, const_cast<sembuf *>(&ops[0]), ops.size()));
256  }
257 #ifdef __API_HAS_SEMTIMEDOP
258  //timeMs: if suspended, wait for timeMs milli-seconds
259  bool timeApply(int index, int op, bool wait, bool undo, uint32_t timeMs){
260  if(!valid())
261  return false;
262  sembuf sb(GenOp(index, op, wait, undo));
263  struct timespec ts;
264  tools::GetRelativeTimespec(timeMs, &ts);
265  return (0 == ::semtimedop(semid_, &sb, 1, &ts));
266  }
267  bool timeApply(const std::vector<sembuf> & ops, uint32_t timeMs){
268  if(!valid())
269  return false;
270  if(ops.empty())
271  return true;
272  struct timespec ts;
273  tools::GetRelativeTimespec(timeMs, &ts);
274  return (0 == ::semtimedop(semid_, const_cast<sembuf *>(&ops[0]), ops.size(), &ts));
275  }
276 #endif
277  //destroy semaphore set from system
278  void destroy(){
279  if(valid()){
280  ::semctl(semid_, 0, IPC_RMID);
281  semid_ = -1;
282  }
283  }
284 private:
285  int semid_;
286 };
287 
288 NS_SERVER_END
289 
290 #endif
291 
Definition: semaphore.hh:24
Definition: semaphore.hh:69
Definition: semaphore.hh:131