藍森林首頁 | 返回主頁 | 本站地圖 | 站內搜索 | 聯繫信箱 |
 您目前的位置:首頁 > 自由軟件 > 技術交流 > 應用編程


    

藍森林 http://www.lslnet.com 2006年6月6日 10:18


寫了個簡單的進程池,大家幫我看看有什麼問題

現在在測試的時候, 子進程不穩定, 有時候,執行到 某個函數時就會莫名其妙的 當掉,

propool.h:
[code]
#ifndef _PROPOOL_H_
#define _PROPOOL_H_

#include <stdio.h>;
#include <stdlib.h>;
#include <memory.h>;
#include <string.h>;
#include <limits.h>;
#include <time.h>;
#include <signal.h>;
#include <fcntl.h>;
#include <dlfcn.h>;
#include <unistd.h>;
#include <errno.h>;
#include <sys/types.h>;
#include <sys/ipc.h>;

#define  FILENAME_LEN 128
#define  OFF_WAITTIME 10
#define  KEY_FILE1    "POOL.shm"
#define  KEY_FILE2    "LOCK.sem"


/***************** 定義枚舉  **********************/
typedef enum EnumPoolStatus                 /* 進程池狀態              */
{
    PSTATUS_ON,                             /* 可用                    */
    PSTATUS_OFF                             /* 不可用                  */
}EPoolStatus;


typedef enum EnumChildProcStatus            /* 子進程狀態              */
{
    CSTATUS_ACT,                            /* 忙碌                    */
    CSTATUS_IDLE                            /* 空閒                    */
}EChildProcStatus;


/***************** 定義結構  **********************/
/* 進程池結構*/
typedef struct StruPool
{
    pid_t               iPid;               /*進程號                    */
    long                lRate;              /*子進程使用次數            */
    long                lLastTime;          /*最近使用時間              */
    long                lPort;              /*子進程偵聽端口號          */
    EChildProcStatus    EStatus;            /*子進程狀態 0:空閒 1:忙碌 */
}Pool;

/*進程池狀態結構*/
typedef struct StruPoolCtrl
{
        EPoolStatus EPoolStatus;                /*進程池可用狀態            */            
    int         iActProcNum;                /*激活(正在使用)的進程數    */
    int         iInitProcNum;               /*初始化進程數              */  
    int         iValidProcNum;              /*有效(總共)進程數        */  
    int         iMaxProcNum;                /*最大進程數                */
}PoolCtrl;

/***************** 全局變量  **********************/
Pool    *g_SPool;
PoolCtrl       *g_SPoolCtrl;
key_t   SEMKEY_LOCK;
key_t   SHMKEY_POOL;
key_t   SHMKEY_POOLCTRL;
[/code]

寫了個簡單的進程池,大家幫我看看有什麼問題

propool.c:

[code]

#include "propool.h"
/*************************************************
函數名稱︰AcceptWait()
函數功能︰對SemLock的封裝
輸入參數︰無
輸出參數︰無
返 回 值︰0 -- 成功
**************************************************/
int AcceptWait()
{
    SemLock(SEMKEY_LOCK);  /*信號燈解鎖*/
   
    return 0;
}

/*************************************************
函數名稱︰AcceptRelease()
函數功能︰對SemLock的封裝
輸入參數︰無
輸出參數︰無
返 回 值︰0 -- 成功
**************************************************/
int AcceptRelease()
{
    SemUnlock(SEMKEY_LOCK);  /*信號燈解鎖*/
   
    return 0;
}
/******************************************************************************
函數名稱: InitPool
函數功能: 進程池初始化
輸入參數: iInitNum -- 初始化進程數
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int InitPool(int iInitNum)
{
    char    sFileName[FILENAME_LEN];
    int     iRet;
    int     ShmID;
   
    memset(sFileName, 0, sizeof(sFileName));
    sprintf(sFileName, "%s/%s/%s", getenv("HOME"), "tmp", KEY_FILE1);
    if(fclose(fopen(sFileName, "w")) == -1)
    {
        return -1;
    }
   
    SHMKEY_POOL = ftok(sFileName, 'a');
    if(SHMKEY_POOL == -1)
    {
        printf("Create SHMKEY ERROR:[%s] \n", strerror(errno));
        return -2;
    }
   
   
   
    SHMKEY_POOLCTRL = ftok(sFileName, 'b');
    if(SHMKEY_POOLCTRL == -1)
    {
        printf("Create SHMKEY ERROR:[%s] \n", strerror(errno));
        return -3;
    }
   
    ShmRemove(SHMKEY_POOL);
    ShmRemove(SHMKEY_POOLCTRL);
   
    /*創建共享內存*/
    ShmID = ShmCreate(SHMKEY_POOLCTRL, sizeof(PoolCtrl));
    if(ShmID < 0 )
    {
        printf("Create SHM error: [%s]\n", strerror(errno));
        return -4;
    }
   
    g_SPoolCtrl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
   
    memset(g_SPoolCtrl, 0, sizeof(g_SPoolCtrl));
   
    /*初始化PoolCtrl結構*/
    g_SPoolCtrl->;EPoolStatus   = PSTATUS_ON;
    g_SPoolCtrl->;iActProcNum   = 0;
    g_SPoolCtrl->;iInitProcNum  = iInitNum;
    g_SPoolCtrl->;iValidProcNum = 0;
    g_SPoolCtrl->;iMaxProcNum   = 0;
   
   
    /*創建共享內存*/
    ShmID = ShmCreate(SHMKEY_POOL, sizeof(Pool) * g_SPoolCtrl->;iInitProcNum);
    if(ShmID < 0 )
    {
        printf("Create SHM error: [%s]\n", strerror(errno));
        
        /*釋放已創建共享內存的資源*/
        ShmUnlink((char *)g_SPoolCtrl);
        ShmRemove(SHMKEY_POOLCTRL);
        
        return -5;
    }
   
    g_SPool = (Pool *)ShmLink(SHMKEY_POOL);
    memset(g_SPool, 0, sizeof(Pool) * g_SPoolCtrl->;iInitProcNum);
   
    /*生成信號燈 的鍵值*/
    memset(sFileName, 0, sizeof(sFileName));
    sprintf(sFileName, "%s/%s/%s", getenv("HOME"), "tmp", KEY_FILE2);
    if(fclose(fopen(sFileName, "w")) == -1)
    {
              
         /*釋放已創建共享內存的資源*/
        ShmUnlink((char *)g_SPoolCtrl);
        ShmUnlink((char *)g_SPool);
   
        ShmRemove(SHMKEY_POOL);
        ShmRemove(SHMKEY_POOLCTRL);
        
        return -6;
    }
   
    SEMKEY_LOCK = ftok(sFileName, 'a');
    SemRemove(SEMKEY_LOCK);
   
    SemInit(SEMKEY_LOCK, 1);
   
    return 0;
}

/******************************************************************************
函數名稱: IncActProcNum
函數功能: 進程池中激活子進程 增加1
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int IncActProcNum()
{
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
   
    SemLock(SEMKEY_LOCK);       /*加鎖*/
    pSPoolCtl->;iActProcNum ++;
    SemUnlock(SEMKEY_LOCK);    /*解鎖*/
        
    return 0;
}

/******************************************************************************
函數名稱: DecActProcNum
函數功能: 進程池中激活子進程 減少1
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int DecActProcNum()
{
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
   
    SemLock(SEMKEY_LOCK);
    pSPoolCtl->;iActProcNum --;
    SemUnlock(SEMKEY_LOCK);
   
    return 0;
}

/******************************************************************************
函數名稱: IncValidProcNum
函數功能: 進程池中有效子進程 增加1
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int IncValidProcNum()
{
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
   
    SemLock(SEMKEY_LOCK);
    pSPoolCtl->;iValidProcNum ++;
    SemUnlock(SEMKEY_LOCK);
    return 0;
}

/******************************************************************************
函數名稱: DecValidProcNum
函數功能: 進程池中有效子進程 減少1
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int DecValidProcNum()
{
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
   
    SemLock(SEMKEY_LOCK);
    pSPoolCtl->;iValidProcNum --;
   
    SemUnlock(SEMKEY_LOCK);
    return 0;
}

/******************************************************************************
函數名稱: GetActProcNum
函數功能: 獲取進程池中激活子進程數
輸入參數: 無
輸出參數: 無
返 回 值: 進程池中激活子進程
******************************************************************************/
int GetActProcNum()
{  
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
    return pSPoolCtl->;iActProcNum;
}

/******************************************************************************
函數名稱: GetValidProcNum
函數功能: 獲取進程池中有效子進程數
輸入參數: 無
輸出參數: 無
返 回 值: 進程池中激活子進程
******************************************************************************/
int GetValidProcNum()
{  
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
   
    return pSPoolCtl->;iValidProcNum;
}

/******************************************************************************
函數名稱: GetInitProcNum
函數功能: 獲取進程池中有效子進程數
輸入參數: 無
輸出參數: 無
返 回 值: 進程池中激活子進程
******************************************************************************/
int GetInitProcNum()
{  
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
   
    return pSPoolCtl->;iInitProcNum;
}

/******************************************************************************
函數名稱: GetValidProcNum
函數功能: 獲取進程池中有效子進程數
輸入參數: 無
輸出參數: 無
返 回 值: 進程池中激活子進程
******************************************************************************/
int GetIdleProcNum()
{   
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
    return pSPoolCtl->;iValidProcNum - g_SPoolCtrl->;iActProcNum;
}

/******************************************************************************
函數名稱: GetPoolStatus
函數功能: 獲取進程池狀態
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 不可用
          1 -- 可用
******************************************************************************/
int GetPoolStatus()
{   
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
   
    if(pSPoolCtl->;EPoolStatus == PSTATUS_OFF)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

/******************************************************************************
函數名稱: SetPoolStatus
函數功能: 獲取進程池狀態
輸入參數: PSTATUS_ON  -- 進程池可用
          PSTATUS_OFF -- 進程池不可用
輸出參數: 無
返 回 值: 0 -- 正常        
******************************************************************************/
static int SetPoolStatus(EPoolStatus status)
{   
    PoolCtrl *pSPoolCtl;
    pSPoolCtl = (PoolCtrl *)ShmLink(SHMKEY_POOLCTRL);
    pSPoolCtl->;EPoolStatus = status;
   
    return 0;
}

/******************************************************************************
函數名稱: SetPoolOn
函數功能: 設置進程池為可用狀態
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 正常        
******************************************************************************/
int SetPoolOn()
{   
    SetPoolStatus(PSTATUS_ON);
   
    return 0;
}

/******************************************************************************
函數名稱: SetPoolOff
函數功能: 設置進程池為不可用狀態
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 正常        
******************************************************************************/
int SetPoolOff()
{   
    SetPoolStatus(PSTATUS_OFF);
   
    return 0;
}

/******************************************************************************
函數名稱: GetChildProcInfo
函數功能: 根據進程號獲取子進程相關信息
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 成功
******************************************************************************/
int GetChildProcInfo(pid_t pid, Pool *SPool)
{  
    int i;
    Pool *pSPool;
    pSPool = (Pool *)ShmLink(SHMKEY_POOL);
   
   
    for(i = 0; i < GetValidProcNum(); i++)
    {
        if(pid == pSPool[i].iPid)
        {
            break;
        }
    }
   
    memcpy(SPool, pSPool + i, sizeof(Pool));
   
    return 0;
}

/******************************************************************************
函數名稱: GetChildProcInfo
函數功能: 根據索引號獲取子進程相關信息
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 成功
******************************************************************************/
int GetChildProcInfoIndex(int index, Pool *SPool)
{   
    Pool *pSPool;
    pSPool = (Pool *)ShmLink(SHMKEY_POOL);
   
    memcpy(SPool, pSPool + index, sizeof(Pool));
        
    return 0;
}

/******************************************************************************
函數名稱: CreateChildProc
函數功能: 進程池初始化
輸入參數: iInitNum -- 初始化進程數
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
static int CreateChildProc(int i, TSocket *sock)
{
    Pool *pSPool;
    pSPool = (Pool *)ShmLink(SHMKEY_POOL);
   
    printf("CreateChildProc......................begin\n");
    pSPool[i].iPid      = getpid();
    pSPool[i].lRate     = 0;
    pSPool[i].EStatus   = CSTATUS_IDLE;
    pSPool[i].lLastTime = 0;
    pSPool[i].lPort     = sock->;LocalPort;

   /*有些進程數 +1*/
    IncValidProcNum();

   
    return 0;
}

/******************************************************************************
函數名稱: CreatePool
函數功能: 進程池初始化
輸入參數: func -- 輸入函數指針
          data -- func函數輸入參數
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int CreatePool(int (*func)(int), int iForkFlag, TSocket *sock, LinkNode *link)
{
    int     i;
    pid_t   pid;
    Module  *pSMod;
    LinkNode *pNode;
   
   
    for(i = 0; i < GetInitProcNum(); i ++)
    {   
        
        SetEnv_tcp(sock, atol(pSMod->;port));
        
       switch((pid = fork()))
        {
        case -1:
            fprintf(stderr, "FORK ERROR : [%s] \n", strerror(errno));
            ClearIPC();
            return -1;
        case 0:
            CreateChildProc(i, sock);
            
            for(;;)
            {
                Accept();
            }
            func();
        default:
            continue;
        
        }
    }
   
    return 0;
}

/******************************************************************************
函數名稱: UseChildProc
函數功能: 使用子進程
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int UseChildProc()
{
    int i;
        pid_t pid;

    Pool *pSPool;
    pSPool = (Pool *)ShmLink(SHMKEY_POOL);
   
        pid = getpid();
       
                for(i = 0; i < GetValidProcNum(); i ++)
        {
                if(pSPool[i].iPid == pid)
                {
                        break;
                }
        }               
       
                /*置進程狀態為忙碌*/
        pSPool[i].EStatus   = CSTATUS_ACT;
                pSPool[i].lLastTime = atol(GetSysTime());
        /*此進程被使用次數 +1*/
        pSPool[i].lRate ++;
       
       
        IncActProcNum();
        return 0;
}

/******************************************************************************
函數名稱: RlsChildProc
函數功能: 釋放子進程
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int RlsChildProc()
{
    int i;
        pid_t pid;

    Pool *pSPool;
    pSPool = (Pool *)ShmLink(SHMKEY_POOL);
   
        pid = getpid();
       
       
        for(i = 0; i < GetValidProcNum(); i ++)
        {
                if(pSPool[i].iPid == pid)
                {
                        break;
                }
        }               
       
       
        /*激活進程數減 1*/
        DecActProcNum();
       
        /*置進程狀態為空閒*/
        pSPool[i].EStatus = CSTATUS_IDLE;
       
        return 0;
}


/******************************************************************************
函數名稱: MonitorPool
函數功能: 監控進程池
輸入參數: 無
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int MonitorPool()
{
    int i;
   
    Pool *pSPool;
    pSPool = (Pool *)ShmLink(SHMKEY_POOL);
   
    while(1)
    {
        for(i = 0; i < GetValidProcNum(); i ++)
        {
            /*
             * 如果為異常進程,則重置此子進程
             */
            if( pSPool[i].iPid >; 0 && kill(pSPool[i].iPid, 0) != 0)
            {
                pSPool[i].iPid      = 0;
                pSPool[i].EStatus   = CSTATUS_IDLE;
                pSPool[i].lRate     = 0;
                pSPool[i].lLastTime = 0;
            }
        }
    }
}


/******************************************************************************
函數名稱: ClearPool
函數功能: 釋放進程池
輸入參數: iFlag -- 是否強制關閉進程池(即 當子進程正在處理交易時,是否強制關閉它)
                   1: 當子進程空閒時 才能被殺掉
輸出參數: 無
返 回 值: 0 -- 成功
         <0 -- 失敗
******************************************************************************/
int ClearPool(int iFlag)
{
    int i;
    time_t t0;
   
    for(i = 0; i < GetValidProcNum(); i ++)
    {
        
        if(iFlag == 1)
        {
            t0 = time(NULL);
            while(g_SPool[i].EStatus == CSTATUS_ACT)
            {
                /*超時時間*/
                if(time(NULL) - t0 >; OFF_WAITTIME)
                {
                    
                    break;
                }
            }
        }
        
        if(g_SPool[i].iPid >; 0)
        {
            
            kill(g_SPool[i].iPid, SIGTERM);
        }
        
    }
   
   
   
        
   
   
    ClearIPC();
    free(g_SPool);
    free(g_SPoolCtrl);
    return 0;
}     

[/code]

寫了個簡單的進程池,大家幫我看看有什麼問題

main.c:
[code]
   
    創建socket鏈接

    InitPool(5);
    CreatePool(func, sockset,......);
    MonitorPool();
[/code]

寫了個簡單的進程池,大家幫我看看有什麼問題

這裡面用到了不少的其它的庫,Shm..., Sem...., Tcp...。

CreateChildProc中,怎麼一個服務的機制沒看的太懂。

只能提點表面的意見了:

全局量一般在c源文件中定義,而不是在頭文件,頭文件最多只放聲明。一般來說,也盡量是封裝全局量

你的monitorpool過程似乎在不停的檢查,沒有個等待?而且你最好也需要先判斷這個pid是不是屬於你的子進程,而不是直接kill.

寫了個簡單的進程池,大家幫我看看有什麼問題

服務是在 CreatePool 函數里 , Accept()偵聽, func()處理

monitorpool 只是針對 pSPool 中的 進程號 不斷掃瞄, 即只針對 進程池中的 子進程 掃瞄

寫了個簡單的進程池,大家幫我看看有什麼問題

子進程負責accept,這個個能在一些系統中需要加入其它的措施。

管理子進程寫了不少,但是如果子進程core dump了(異常退出),怎麼處理?至少應該有restart子進程和初始化該進程資源的功能。

寫了個簡單的進程池,大家幫我看看有什麼問題

monitorpool 只是針對 pSPool 中的 進程號 不斷掃瞄, 即只針對 進程池中的 子進程 掃瞄

這種掃面是浪費CPU,用以個簡單的進程建通信的機制便可,例如pipe都可以,這樣讓發生變化的子進程來喚醒父進程,這樣實現管理可能效率能高一些。

寫了個簡單的進程池,大家幫我看看有什麼問題

monitorPool現在寫的比較簡單,
對於子進程異常中止, 或 coredump ,  應重新fork 一個子進程



Copyright © 1999-2000 LSLNET.COM. All rights reserved. 藍森林網站 版權所有。 E-mail : webmaster@lslnet.com