共有メモリを使用したスタンドアロン操作単位時間制限クラス

6936 ワード

≪シーンの使用|Use Scene|emdw≫:単一マシン上で複数のプロセスが同じサービスを実行し、あるリクエストまたは他のものの各時間の実行回数を制限することを望んでいる場合は、このクラスを使用します.
#ifndef ACTIVITY_LIMIT_REQUEST_ACTION_H_
#define ACTIVITY_LIMIT_REQUEST_ACTION_H_


#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <string>
#include <cmath>

using namespace std;


/**          **/
typedef struct shm_data
{
	struct timeval tv;
	unsigned int uiNumber;
}SRequestLimitStruct;

static const int TIME_SIZE = sizeof(struct timeval);
static const int COUNT_SIZE = sizeof(SRequestLimitStruct) - TIME_SIZE;

class CLimitRequestAction
{
public:

	union semun
	{
		int val;                   /*value for SETVAL*/
		struct semid_ds *buf;      /*buffer for IPC_STAT & IPC_SET*/
		unsigned short int *array; /*array for GETALL & SETALL*/
		struct seminfo *__buf;     /*buffer for IPC_INFO*/
	};

	/*          :           ,     1 */
	int binary_semaphore_wait(int semid)
	{
		struct sembuf sem_b;
		sem_b.sem_num = 0;
		/*   。 */
		sem_b.sem_op = -1;
		/*        */
		sem_b.sem_flg = SEM_UNDO;
		return semop (semid, &sem_b, 1);
	}

	/*               :     。           */
	int binary_semaphore_post (int semid)
	{
		struct sembuf sem_b;
		/*   (    )       */
		sem_b.sem_num = 0;
		/*    */
		sem_b.sem_op = 1;
		/*        */
		sem_b.sem_flg = SEM_UNDO;  //      (        ),          semop()     。                              ,         。
		return semop (semid, &sem_b, 1);
	}

	CLimitRequestAction()
	{
		bzero(m_szErrMsg, sizeof(m_szErrMsg));
		iInitSuccess = 0;
	}

	~CLimitRequestAction()
	{
		shmdt((char *)m_pshm);
	}

	static CLimitRequestAction * Instance()
	{
		static CLimitRequestAction ms_inst;
		return &ms_inst;
	}

	int init(key_t keyShm, key_t keySem)
	{
		m_keyShm = keyShm;
		m_keySem = keySem;

		/**           **/
		m_iSemId = semget(m_keySem, 1, 0666 | IPC_CREAT | IPC_EXCL);  //   key   ((semflg &IPC_CREAT) &&(semflg &IPC_EXCL)) 0,   semget  EEXIST
		if (m_iSemId < 0 && errno != EEXIST)
		{
			snprintf(m_szErrMsg, sizeof(m_szErrMsg)-1, "semget failed. keySem:%u, iSemId:%d, msg:%s", m_keySem, m_iSemId, strerror(errno));
			return -1;
		}
		if(m_iSemId >= 0) //            ,    
		{
			/*        */
			semun sem_union;
			sem_union.val = 1;
			if(semctl(m_iSemId, 0, SETVAL, sem_union) == -1)
			{
				snprintf(m_szErrMsg, sizeof(m_szErrMsg)-1, "semctl failed. keySem:%u, iSemId:%d, msg:%s", m_keySem, m_iSemId, strerror(errno));
				return -2;
			}
		}
		else  //          ,           
		{
			m_iSemId = semget(m_keySem, 1, 0666);
			if(m_iSemId < 0)
			{
				snprintf(m_szErrMsg, sizeof(m_szErrMsg)-1, "semget failed. keySem:%u, iSemId:%d, msg:%s", m_keySem, m_iSemId, strerror(errno));
				return -1;
			}
		}

		/**         **/
		m_iShmId = shmget(m_keyShm, sizeof(SRequestLimitStruct), IPC_CREAT|0666); //       IPC_CREAT,shmget()                     ,                 
		if(m_iShmId < 0)
		{
			snprintf(m_szErrMsg, sizeof(m_szErrMsg)-1, "shmget failed. keyShm:%u, iShmid:%d, msg:%s", m_keyShm, m_iShmId, strerror(errno));
			return -3;
		}

		m_pshm = (SRequestLimitStruct *)shmat(m_iShmId, NULL, 0); //                     
		if( (char*)(void*)m_pshm  == (char *)-1)
		{
			snprintf(m_szErrMsg, sizeof(m_szErrMsg)-1, "shmat failed. keyShm:%u, iShmid:%d, msg:%s", m_keyShm, m_iShmId, strerror(errno));
			return -4;
		}
		iInitSuccess = 1;
		return 0;
	}


	/********************************
	*    cgi    ,                                
	* @keySem:   key
	* @keyShm:     key
	* @uiLimitCount:        
	* @uiInterval:        
	*    : 0  ,0   bIfLimit         
	********************************/
	int RequestNumberLimit(const struct timeval &tvNow, bool &bIfLimit, unsigned int uiLimitCount, unsigned int uiInterval = 1000)
	{
		bIfLimit = false;
		if(binary_semaphore_wait(m_iSemId)) // P  ,        
		{
			snprintf(m_szErrMsg, sizeof(m_szErrMsg)-1, "wait semop failed. keySem:%u, iSemId:%d, msg:%s", m_keySem, m_iSemId, strerror(errno));
			shmdt((char *)m_pshm);
			exit(-1);
		}

		long long msNow = tvNow.tv_sec*1000 + tvNow.tv_usec/1000;
		long long msLastRequestTime = m_pshm->tv.tv_sec * 1000 + m_pshm->tv.tv_usec/1000;

		//		printf("msNow is %lld, msLastRequestTime is %lld, abs(msNow - msLastRequestTime) is %lld
", msNow, msLastRequestTime, abs(msNow - msLastRequestTime)); if(abs(msNow - msLastRequestTime) > uiInterval) // , { m_pshm->uiNumber = 0; m_pshm->tv.tv_sec = tvNow.tv_sec; m_pshm->tv.tv_usec = tvNow.tv_usec; } else { if(m_pshm->uiNumber >= uiLimitCount) { if(binary_semaphore_post(m_iSemId)) { snprintf(m_szErrMsg, sizeof(m_szErrMsg)-1, "post semop failed. keySem:%u, iSemId:%d, msg:%s", m_keySem, m_iSemId, strerror(errno)); shmdt((char *)m_pshm); exit(-1); } bIfLimit = true; return 0; } } ++(m_pshm->uiNumber); if(binary_semaphore_post(m_iSemId)) { snprintf(m_szErrMsg, sizeof(m_szErrMsg)-1, "post semop failed. keyShm:%u, keySem:%u, iSemId:%d, msg:%s", m_keyShm, m_keySem, m_iSemId, strerror(errno)); shmdt((char *)m_pshm); exit(-1); } return 0; } /******************************** * ********************************/ string GetErrMsg(void) { return m_szErrMsg; } public: int iInitSuccess; // private: key_t m_keyShm; key_t m_keySem; int m_iShmId; // ID int m_iSemId; // ID SRequestLimitStruct* m_pshm; char m_szErrMsg[1024]; };

例:
#include "activity_limit_request_action.h"
#include <sys/time.h>

int main(int argc, char *argv[])
{
    if(argc < 2)
    {
        printf("usgae: %s count
", argv[0]); return -1; } int iCount = atoi(argv[1]); bool bIfLimit; for(int i = 0; i < iCount; i++) { static bool bInit = false; if(bInit == false) { int iRet = CLimitRequestAction::Instance()->init(0x20131118,0x20131118); printf("asdadadasdas
"); if(iRet != 0) { printf("init failed.
"); return -1; } bInit = true; } struct timeval tvNow; gettimeofday(&tvNow, NULL); int iRet = CLimitRequestAction::Instance()->RequestNumberLimit(tvNow, bIfLimit, 50); printf("pid:%d, i:%d, iRet:%d, bIfLimit:%d, msg:%s
", getpid(), i, iRet, bIfLimit, CLimitRequestAction::Instance()->GetErrMsg().c_str()); // usleep(5); } return 0; }

複数のプロセスを同時に実行できるコピー