多线程记录二进制流文件

一个生产者多消费者的应用 , 代码里目前就先简单用了单生成单消费,

每一局麻将都需要记录:每一次的发牌,抓牌,出牌 ,吃碰杠胡听;

把所有的牌 序列化成二进制存入文件

每一局麻将生成一个key  , 可随意自己组合

 

下面代码思路仅供参考, 还未测试过; 可修改成多线程日志

主线程唯一需要在开始的时候调用一次 start ,  记录用push;

2种模式可选, 一种不关闭文件handle, 直到一局游戏结束,再关闭

一种每次打开,写入,关闭;

 

2种写入方式, 一种写入2进制流 ,

一种把2进制流转成一个个unsigned long储存在文件

[ 14张牌从 0x01 ~ 0x48 ]  0x48需要 7 位,因此每张牌用7位来储存,最多 98 位,

对于一个unsigned long 最多储存 4 张牌,  因此有14张牌时需要 4个unsigned long

 


class ErrorInfo{
    static const SIZE_T ERR_MSG_SIZE = 1 << 13;
    static CRITICAL_SECTION err_cs;
    static std::once_flag oneflag;
public:
    static void init(){
        std::call_once(ErrorInfo::oneflag,&ErrorInfo::init_cs);
    }
    static void init_cs(){
           InitializeCriticalSectionAndSpinCount(&ErrorInfo::err_cs, 4000);
    }

    static std::string getError(DWORD err){
        EnterCriticalSection(&ErrorInfo::err_cs);
        static HANDLE g_heap = HeapCreate(0, ERR_MSG_SIZE, 0);
        static char *buf = (char*)HeapAlloc(g_heap, 0, ERR_MSG_SIZE);
        static std::string errstr;
        static std::stringstream ss;
        ss.str("");
        ss.clear();
        errstr.clear();
        DWORD syslocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
        DWORD ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, err, syslocale, buf, ERR_MSG_SIZE, NULL);

        if (!ret){
            static HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
            if (hDll){
                //如果在dll中查找,FORMAT_MESSAGE_FROM_HMODULE 添加上去, 第2个参数填写句柄
                ret = FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                    hDll, err, syslocale, buf, ERR_MSG_SIZE, NULL);
            }
        }
        if (ret && buf){
            buf[ret] = 0;
            errstr = buf;
            LeaveCriticalSection(&ErrorInfo::err_cs);
            return errstr;
        }
        ss << err;
        ss >> errstr;
        LeaveCriticalSection(&ErrorInfo::err_cs);
        return errstr;
    }
};
CRITICAL_SECTION ErrorInfo::err_cs;
std::once_flag ErrorInfo::oneflag;

#include <bitset>
struct  FileHandleData{
    HANDLE hFile;
    volatile bool inUse;
    std::string filepath;
    FileHandleData(HANDLE file = INVALID_HANDLE_VALUE, bool inUse = false):hFile(file),inUse(inUse){}
};
struct  storeData{
    std::string key;  //随意的key
    std::string data; //数据
    int type; //类型[抓牌,出牌,吃碰杠等]
    int seat; //座位号
    storeData(const char * key, const char *data , int nDataLen , int type, int seat):key(key),data(data,nDataLen) , type(type) , seat(seat){}
    storeData(storeData && obj) throw() : key(std::move(obj.key)),data(std::move(obj.data)) , type(obj.type) , seat(obj.seat){}
    storeData & operator=(storeData && obj) throw(){
        if(this != &obj){
            key = std::move(obj.key);
            data = std::move(obj.data);
            type = obj.type;
            seat = obj.seat;
        }
        return *this;
    }
};
struct restoreData{
   int nLen;
   int type;
   int seat;
   char handCards[14];
   char buf[0];
};

class RecordFile
{
    CRITICAL_SECTION write_cs;
    CRITICAL_SECTION prepare_cs;
    CRITICAL_SECTION errlog_cs;
    CONDITION_VARIABLE write_cond;
    HANDLE hSem;
    deque<storeData> prepare_queue;
    deque<std::string> wait_for_close_queue;
    deque<storeData> write_queue;
    std::unordered_map<std::string,FileHandleData> write_map;
    HANDLE hThreadProducer;
    unsigned tid_producer;
    HANDLE hThreadConsumers[4];
    unsigned tid_consumers[4];
    bool bStopPrepare;
    bool bStopProcess;
    bool bAllDone;
    bool bStarted;
    int m_writeThreadCcount;
    int m_operate;
    int m_writeMode;
    std::string cur_dir_name;
    HANDLE hErrorLog;
    std::string errorLogPath;
    std::list<restoreData*> m_restoreList;
public:
    enum eOperate { OPENFILE = 1, CLOSEFILE = 2};
    enum eSpinCount { SpinCountMin = 1000, SpinCountNormal = 2000, SpinCountMax = 4000};
    enum eSemaphoreCount{ SemMin = 200 , SemNormal = 1000 , SemMax = 2000};
    enum eWriteMode{ WriteModeStream = 1, WriteModeLong = 2};

    RecordFile(int operate =CLOSEFILE ,int writeMode = WriteModeStream, int writeThreadCount = 1):bAllDone(false),
        bStarted(false),
        bStopProcess(false),
        bStopPrepare(false),
        m_operate(operate),m_writeMode(writeMode),
        m_writeThreadCcount(writeThreadCount)
    {
        cur_dir_name = std::string(typeid(*this).name()).substr(6);
        errorLogPath = cur_dir_name + "/errorlog.log";
        ErrorInfo::init();

    }
    void push(const char * key, const char * data , int nDataLen, int type , int seat){
        EnterCriticalSection(&prepare_cs);
        prepare_queue.emplace_back(key,data,nDataLen, type , seat);
        LeaveCriticalSection(&prepare_cs);
        ReleaseSemaphore(hSem,1,0);
    }
    void start(){
        if(bStarted)
            return;
        if(!(OPENFILE == m_operate || CLOSEFILE  == m_operate )){
            return;
        }
        bStarted = true;
        bAllDone = false;
        bStopProcess = false;
        bStopPrepare = false;
        hThreadProducer = NULL;
        memset(hThreadConsumers,0,sizeof(hThreadConsumers));
        InitializeCriticalSectionAndSpinCount(&write_cs , SpinCountMax);
        InitializeCriticalSectionAndSpinCount(&prepare_cs , SpinCountMax);
        InitializeCriticalSectionAndSpinCount(&errlog_cs , SpinCountMax);
        InitializeConditionVariable(&write_cond);

        hSem = CreateSemaphoreW(0,0,SemMax,NULL);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值