12位数唯一ID - 代码可靠性

时间:2009-03-25 08:32:10

标签: c++ unique uniqueidentifier

我想要一个在一天(24小时)内保持独特的数字。以下是我提出的代码;我想知道它的谬误/可能的风险; “我相信'这保证了至少一天的12位数唯一数字。

逻辑是获取当前日期/时间(hhmmssmmm)并连接查询性能计数器结果的前四个字节。

__forceinline bool GetUniqueID(char caUID[MAX_STRING_LENGTH])
{
    //Logic: Add HHMMSSmmm with mid 3 bytes of performance counter.
    //Guarantees that in a single milli second band (0 to 999) the three bytes 
    //of performance counter would always be unique.
    //1. Get system time, and use
    bool bStatus = false;
    try
    {

        SYSTEMTIME localtime;
        GetLocalTime(&localtime);//Get local time, so that we may pull out HHMMSSmmm

        LARGE_INTEGER li;
        char cNT[MAX_STRING_LENGTH];//new time.
        memset(cNT, '\0', sizeof(cNT));
        try
        {
            //Try to get the performance counter,
            //if one is provided by the OEM.

            QueryPerformanceCounter(&li);//This function retrieves the current value of the 
                                         //high-resolution performance counter if one is provided by the OEM
                                         //We use the first four bytes only of it.
            sprintf(cNT, "%u", li.QuadPart);
        }
        catch(...)
        {
            //Not provided by OEM.
            //Lets go with the GetTickCounts();
            //ddHHMMSS + 4 bytes of dwTicks
            sprintf(cNT,"%04d", GetTickCount());
        }


        //Get the first four bytes.
        int iSkipTo     = 0;//This is incase we'd decide to pull out next four bytes, rather than first four bytes.
        int iGetChars   = 4;//Number of chars to get.
        char *pSub = (char*) malloc(iGetChars+1);//Clear memory
        strncpy(pSub, cNT + iSkipTo, iGetChars);//Get string
        pSub[iGetChars] = '\0'; //Mark end.

        //Prepare unique id
        sprintf(caUID, "%02d%02d%02d%3d%s", 
                                    localtime.wHour, 
                                    localtime.wMinute, 
                                    localtime.wSecond, 
                                    localtime.wMilliseconds, 
                                    pSub); //First four characters concat.

        bStatus = true;
    }
    catch(...)
    {
        //Couldnt prepare. There was some problem.
        bStatus = false;
    }

    return bStatus;
}

以下是我得到的输出:

独特:[125907 462224] 独特:[125907 462225] 独特:[125907 462226] 独特:[125907 462227] 独特:[125907 462228] 独特:[125907 462230] 独特:[125907 462231] 独特:[125907 462232] 独特:[125907 462233] 独特:[125907 462234] 独特:[125907 462235] 独特:[125907 462237] 独特:[125907 462238] 独特:[125907 462239] 独特:[125907 462240] 独特:[125907 462241] 独特:[125907 462243] 独特:[125907 462244] 独特:[125907 462245] 独特:[125907 462246] 独特:[125907 462247] 独特:[125907 462248] 独特:[125907 462249] 独特:[125907 462251] 独特:[125907 462252] 独特:[125907 462253] 独特:[125907 462254] 独特:[125907 462255] 独特:[125907 462256] 独特:[125907 462257] 独特:[125907 462258] 毫秒改变了,46 独特:[125907 622261] 独特:[125907 622262] 独特:[125907 622263] 独特:[125907 622264] 独特:[125907 622265] 独特:[125907 622267] 独特:[125907 622268] 独特:[125907 622269] 独特:[125907 622270] 独特:[125907 622271] 独特:[125907 622273] 独特:[125907 622274] 独特:[125907 622275] 独特:[125907 622276] 独特:[125907 622277] 独特:[125907 622278] 独特:[125907 622279] 独特:[125907 622281] 独特:[125907 622282] 独特:[125907 622283] 独特:[125907 622284] 独特:[125907 622285] 独特:[125907 622286] 独特:[125907 622288] 独特:[125907 622289] 独特:[125907 622290] 独特:[125907 622291] 独特:[125907 622292] 独特:[125907 622293] 独特:[125907 622295] 独特:[125907 622296] 独特:[125907 622297] 独特:[125907 622298] 独特:[125907 622299] 独特:[125907 622300] 独特:[125907 622301] 独特:[125907 622302] 独特:[125907 622304] 独特:[125907 622305] 独特:[125907 622306] 毫秒改变,62 独特:[125907 782308] 独特:[125907 782310] 独特:[125907 782311] 独特:[125907 782312] 独特:[125907 782313] 独特:[125907 782314] 独特:[125907 782316] 独特:[125907 782317] 独特:[125907 782318] 独特:[125907 782319] 毫秒改变了,125 独特之处:[1259071402495] 独特之处:[1259071402497] 独特之处:[1259071402498] 独特之处:[1259071402499] 独特之处:[1259071402500] 独特之处:[1259071402502] 独特之处:[1259071402503] 独特之处:[1259071402504] 独特之处:[1259071402505] 独特:1259071402507]

现在我正在考虑将生成的ID保留在列表中,并将新生成的ID与列表中的现有ID进行比较。如果它已经存在于列表中,那么我当然可以跳过这个数字并生成另一个数字,但当然也很清楚这个逻辑会失败。

感谢您的意见/建议/更新/等。

由于 JT。

6 个答案:

答案 0 :(得分:1)

如果您在单核处理器上从一台计算机上运行它,那么逻辑对我来说似乎很合理。然而,我不知道对于连续呼叫的多核处理器是否也是如此。但是,生成的数字在机器上绝对不会是唯一的。

出于好奇,您有没有使用GUID的原因?

或者,由于您正在考虑将生成的ID保留在列表中进行比较,为什么不能创建生成器?由于您建议存储是一个选项,如果您存储最后使用的数字并在每次使用时递增...如果您愿意,您甚至可以存储日期并每天重置计数器。

答案 1 :(得分:1)

我的解决方案是获取系统时间并添加一个计数器(伪代码):

static int counter = 0;
static Time lastTime;

String getNextId() {
    Time now = System.getTime();
    if (lastTime == now)
        counter ++;
    else
        counter = 0;
    return now+counter;
}

即使我在getTime()更改时更频繁地调用该方法,这也可以保证我获得一个新的ID。

答案 2 :(得分:0)

我遇到了快速循环中的时间问题,尽管它们应该是常识,但它们没有改变(你无法控制操作系统,所以你不能认为时间每隔x毫秒就会改变等等)。 / p>

将计数器值添加为额外的几位数(不作为增量)并在重启时或9999之后重置它应该隐藏这一点,以使其完全无法发生(着名的最后一句话)。

格式是TTTTTToooo,其中T是你的时间数字和你的4位数偏移量。

答案 3 :(得分:0)

亚伦:谢谢你的评论,我用你的方法来得到我想要的东西。

__forceinline bool GetUniqueIDEx(char caUID[MAX_STRING_LENGTH])
{
    //Logic: Add HHMMSSmmm with 3 bytes counter.
    //Guarantees a unique number for a calendar date, 
    //that in a single milli second band (0 to 999) the three bytes 
    //of counter would always be unique.
    //1. Get system time, and use

    bool bStatus = false;
    try
    {
        GetLocalTime(&localtime);//Get local time, so that we may pull out HHMMSSmmm

        char cNT[MAX_STRING_LENGTH];//new time.
        memset(cNT, '\0', sizeof(cNT));
        if(m_nCounter> MAX_COUNTER_LIMIT)
        {
            m_nCounter= 0;
        }

        sprintf(cNT, "%03d", ++m_nCounter);

        //Prepare unique id
        sprintf(caUID, "%02d%02d%02d%03d%s", 
                                            localtime.wHour, 
                                            localtime.wMinute, 
                                            localtime.wSecond, 
                                            localtime.wMilliseconds, 
                                            cNT); 

        bStatus = true;
    }
    catch(...)
    {
        //Couldnt prepare. There was some problem.
        bStatus = false;
    }

    return bStatus;
}

答案 4 :(得分:0)

我会从午夜开始使用秒,然后是计数器。这样每秒可以获得高达一千万次点击。应该是非常独特的。使用上面的Aaron代码,将字符串格式化为:

sprintf(idstr, "%05d%07d", secs_since_midnight, counter);

当然,我还坚信使用base-36(通过itoa),当你真的想把一个计数器塞进几个可打印的角色(和一年中的一天,而不是一个月/一天等)< / p>

答案 5 :(得分:0)

我不确定您的流程是否可以牺牲微小的性能问题并保持逻辑简单。

如果您在两次调用之间将进程置于休眠状态1毫秒,我们可以使用HHMMSSmmm格式保证唯一编号。通过这种方式,您可以消除串联部分以及您必须维护的列表,以便仔细检查唯一性。

Manikanthan Velayutham //编程思考BIG