12-значный уникальный идентификатор - надежность кода - PullRequest
0 голосов
/ 25 марта 2009

Я хотел, чтобы число оставалось уникальным в течение дня (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]

Теперь я думаю о том, как сохранить сгенерированные идентификаторы в списке и сравнить новые сгенерированные с существующими в списке. Если он уже существует в списке, то, конечно, я могу пропустить число и сгенерировать другое, но, безусловно, эта логика потерпит неудачу.

Буду признателен за ваши комментарии / предложения / обновления / и т. Д.

Спасибо JT.

Ответы [ 6 ]

1 голос
/ 25 марта 2009

Моим решением было получить системное время и добавить счетчик (псевдокод):

static int counter = 0;
static Time lastTime;

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

Это гарантирует, что я получу новый идентификатор, даже когда я вызываю метод чаще, чем getTime().

1 голос
/ 25 марта 2009

Логика кажется мне правильной, если вы запускаете ее с одной машины на одноядерном процессоре. Однако я не знаю, верно ли то же самое для многоядерного процессора для последовательных вызовов. Однако сгенерированные числа не будут уникальными для разных машин.

Из любопытства, есть ли причина, по которой вы не используете GUID?

Или, поскольку вы рассматриваете возможность сохранения сгенерированных идентификаторов в списке для сравнения, почему вы не можете создать генератор? Поскольку вы предлагаете сохранение, это вариант, если вы сохраняете последний использованный номер и увеличиваете его при каждом использовании ... Вы можете даже сохранять дату и сбрасывать счетчик каждый день, если хотите.

0 голосов
/ 11 ноября 2009

Я не уверен, может ли ваш процесс пожертвовать крошечной проблемой производительности и сохранить логику простой.

Мы можем гарантировать уникальный номер в формате HHMMSSmmm, если перевести процесс в спящий режим на 1 миллисекунду между двумя вызовами. Таким образом вы можете исключить часть конкатенации, а также список, который вы должны вести, чтобы дважды проверить уникальность.

Manikanthan Velayutham // запрограммирован, чтобы думать БОЛЬШОЙ

0 голосов
/ 27 апреля 2009

Я бы использовал секунды с полуночи, а затем счетчик. Это дает вам до десяти миллионов хитов в секунду. Должно быть довольно уникальным. Используя приведенный выше код Аарона, вы форматируете строку как:

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

Конечно, я также твердо верю в использование base-36 (через itoa), когда вы действительно хотите втиснуть счетчик в несколько печатных символов (и день года, а не месяц / день и т. Д.)

0 голосов
/ 03 апреля 2009

Аарон: Спасибо за ваши комментарии, я использовал ваш подход, чтобы получить то, что я хотел.

__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;
}
0 голосов
/ 25 марта 2009

У меня были проблемы со временем в быстрых циклах, когда они не изменились, несмотря на здравый смысл, которым они должны (вы не можете контролировать ОС, поэтому не можете предполагать, что время меняется каждые x миллисекунд и т. 1001 *

Добавление значения счетчика в виде нескольких дополнительных цифр (не в виде приращения) и сброс его при перезапуске или после 9999 должно скрыть это достаточно, чтобы сделать это практически невозможным (известные последние слова).

форматом тогда будет TTTTTToooo, где T - ваше значение времени и o ваше 4-значное смещение.

...