最近为了对多进程互斥访问资源,采用System V的命名信号量,为了方便使用,对其用c++进行了封装,代码如下.
AOSLock.hpp:
#ifndef _AOSLOCK_HPP
#define _AOSLOCK_HPP
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
typedef enum
{
SEM_FAIL=-1,
SEM_OK,
SEM_BUSY
} SEM_RET_VALUE;
union semun
{
int val;
struct semid_ds* buf;
};
class AOSLock
{
private:
int semId_;
key_t key_;
int resNum_;
public:
AOSLock();
AOSLock(const char* keyPathName);
int initialLock(int resNum);
int getVal();
void enter1();
void leave1();
void enterN(int resNum);
void leaveN(int resNum);
int enterN_NO_WAIT(int resNum); // return SEM_BUSY or SEM_OK or SEM_FAIL
void leaveN_NO_WAIT(int resNum);
void releaseLock();
};
#endif
AOSLock.cpp:
#include "AOSLock.hpp"
AOSLock::AOSLock()
{
key_ = ftok("/root", 1);
}
AOSLock::AOSLock(const char* keyPathName)
{
key_ = ftok(keyPathName, 1);
}
int AOSLock::initialLock(int resNum)
{
semId_ = semget(key_, 1, 0666|IPC_CREAT|IPC_EXCL);
// printf("sem id=%d/n",semId_);
if (semId_ < 0)
{
//perror("semget");
// int tmpErrno = errno;
//printf("errno=%d, expected=%d/n", errno, EEXIST);
//if (tmpErrno == EEXIST)
{
// printf("exist/n");
semId_ = semget(key_, 1, 0666|IPC_CREAT);
}
}
else
{
// printf("first time/n");
resNum_ = resNum;
union semun arg;
arg.val=resNum;
if (semctl(semId_, 0, SETVAL, arg) < 0)
{
// perror("semctl");
}
}
// printf("sem id_ =%d/n",semId_);
/* int value = semctl(semId_, 0, GETVAL);
if (value < 0)
{
perror("semctl");
}
printf("sem value=%d/n", value);*/
return semId_;
}
int AOSLock::getVal()
{
int value = semctl(semId_, 0, GETVAL);
if (value < 0)
{
// perror("semctl");
}
// printf("sem value=%d/n", value);
return value;
}
void AOSLock::enter1()
{
struct sembuf p_buf;
p_buf.sem_num=0;
p_buf.sem_op=-1;
p_buf.sem_flg=SEM_UNDO;
semop(semId_,&p_buf,1);
}
void AOSLock::leave1()
{
struct sembuf v_buf;
v_buf.sem_num=0;
v_buf.sem_op=1;
v_buf.sem_flg=SEM_UNDO;
semop(semId_,&v_buf,1);
}
void AOSLock::enterN(int resNum)
{
struct sembuf p_buf;
p_buf.sem_num=0;
p_buf.sem_op=-resNum;
p_buf.sem_flg=SEM_UNDO;
semop(semId_,&p_buf,1);
}
void AOSLock::leaveN(int resNum)
{
struct sembuf v_buf;
v_buf.sem_num=0;
v_buf.sem_op=resNum;
v_buf.sem_flg=SEM_UNDO;
semop(semId_,&v_buf,1);
}
void AOSLock::releaseLock()
{
if(semctl(semId_,0,IPC_RMID)==-1)
perror("semctl");
}
int AOSLock::enterN_NO_WAIT(int resNum)
{
struct sembuf p_buf;
p_buf.sem_num=0;
p_buf.sem_op=-resNum;
p_buf.sem_flg=IPC_NOWAIT;
if (semop(semId_,&p_buf,1) < 0)
{
if(errno == EAGAIN)
{
return SEM_BUSY;
}
else
{
return SEM_FAIL;
}
}
return SEM_OK;
}
void AOSLock::leaveN_NO_WAIT(int resNum)
{
struct sembuf v_buf;
v_buf.sem_num=0;
v_buf.sem_op=resNum;
v_buf.sem_flg=IPC_NOWAIT;
semop(semId_,&v_buf,1);
}