Надежность 12 - Значного Уникального идентификационного кода

StackOverflow https://stackoverflow.com/questions/680683

  •  22-08-2019
  •  | 
  •  

Вопрос

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

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

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

Спасибо Джей Ти.

Это было полезно?

Решение

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

static int counter = 0;
static Time lastTime;

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

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

Другие советы

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

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

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

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

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

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

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

__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;
}

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

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

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

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

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

Маникантхан Велаютхам // запрограммирован мыслить МАСШТАБНО

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top