Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.14.6.194] |
|
Сообщ.
#1
,
|
|
|
Я всю голову себе сломал, пока искал ошибку. У меня одновременно выполняется несколько экземпляров одного процесса, который использует random для создания имени временного файла. И похоже, когда такая операция выполняется в двух процессах в одно и то же время, random в этих процессах иногда генерят одинаковое имя файла. Это я туплю или мне нужен другой random?
|
Сообщ.
#2
,
|
|
|
randomize инициирует начало последовательности с помощью текущего счетчика времени. Поэтому - да, такое в принципе возможно, хотя и маловероятно, что значения QueryPerformanceCounter совпадут.
|
Сообщ.
#3
,
|
|
|
Цитата shershen @ Самым простым выходом будет при создании потока создавать случайное значение для каждого процесса, допустим, от 5 до 21 (либо id назначать потоку, и использовать его за основу) на это время перед вызовом random ложить процесс в сон на его случайное количество миллисекунд. Это решит проблему одновременного опроса счетчика производительности, на основе которого и делается случайное число. операция выполняется в двух процессах в одно и то же время |
Сообщ.
#4
,
|
|
|
Цитата simsergey @ Ну, так: бац и совпали эти "случайные" значения. Что делать? Самым простым выходом будет при создании потока создавать случайное значение для каждого процесса |
Сообщ.
#5
,
|
|
|
Есть же GetTempFileName, зачем изобретать велосипед?
В библиотеке DelphiFundamentals есть несколько своих алгоритмов рандома, чё-то там даже можно задавать свою энтропию. Ну или крипто-хороший PRNG от synopse http://blog.synopse.info/post/AES-CSPRNG |
Сообщ.
#6
,
|
|
|
Цитата shershen @ Это я туплю или мне нужен другой random? Нужно модифицировать инициализацию переменной RandSeed. Например, после вызова Randomize можно поксорить значение RandSeed с GetCurrentThreadID или с Form1.Handle, которые являются уникальными для разных экземпляров одного приложения |
Сообщ.
#7
,
|
|
|
leo
Это не гарантирует уникальность результата - идентификаторы могут различаться в тех же битах, что и счетчики. |
Сообщ.
#8
,
|
|
|
Если нужен совсем-совсем уникальный рэндом - то генери ГУИД.
Для менее суровых случаев - #6 Для файлов действительно уже есть требуемая функция. К тому же, если файл назначения уже существует, то что мешает повторить генерацию имени until not FileExist? |
Сообщ.
#9
,
|
|
|
Цитата MBo @ Это не гарантирует уникальность результата - идентификаторы могут различаться в тех же битах, что и счетчики. Согласен. Тогда можно как-то так: RandSeed:=(RandSeed shl 16) + GetCurrentThreadID (считаем, что в "нормальных условиях" ID потока не превышает High(word)) |
Сообщ.
#10
,
|
|
|
Цитата MBo @ Это не гарантирует уникальность результата - идентификаторы могут различаться в тех же битах, что и счетчики. Можно просто привязаться к астрономической дате и времени запуска процесса (до мс) и(или) ID процесса. (Вряд ли процессы запускаются абсолютно одновременно.) Оба этих параметра могут быть просто составной частью имени файла, без всяких случайных чисел. Если несколько временных файлов процессу одновременно необходимы, в имя или расширение просто добавим счётчик. |
Сообщ.
#11
,
|
|
|
ЫукпШ
Цитата Можно просто привязаться к астрономической дате и времени запуска процесса (до мс) и(или) ID процесса. (Вряд ли процессы запускаются абсолютно одновременно.) Так автор утверждает, что randomize (который в большинстве случаев нано-микросекундный QueryPerformanceCounter использует), часто дает одинакоый результат. (Правда, его кода мы не видели) |
Сообщ.
#12
,
|
|
|
Цитата MBo @ ЫукпШ Цитата Можно просто привязаться к астрономической дате и времени запуска процесса (до мс) и(или) ID процесса. (Вряд ли процессы запускаются абсолютно одновременно.) Так автор утверждает, что randomize (который в большинстве случаев нано-микросекундный QueryPerformanceCounter использует), часто дает одинакоый результат. (Правда, его кода мы не видели) Так я и говорю: 1. для создания имени временного файла случайное число вообще не нужно. Пусть это имя будет состоять из "SomeName"+ID процесса. Или "SomeName" + ID + Date + time (дата и время создания процесса). Понятно, что цифры надо преобразовать в текст. 2. 1-е псевдо - случайное число всегда одно и то-же. Подтверждаю. На то оно и псевдо-случайное, и это даже хорошо. (Вообще, это очень ценное свойство.) Дальше можно поступить способом п 1. Возьмём переменные даты и времени при старте программы, как числа, сложим, и "встряхнём" генератор псевдо-случайных чисел столько раз, каким получилась сумма. И после этого будем использовать случайные числа. Чтобы программа, использующая случайные числа работала не одинаково при каждом запуске. --- Но для данного случая случайные числа не годятся в принципе. Что с ними не делай, они могут совпасть. Их использование в данном случае принципиально вредно. |
Сообщ.
#13
,
|
|
|
Спасибо большое за ответы! Мне понравился вариант с id процесса и датой, но уже решил проблему по другому.
|
Сообщ.
#14
,
|
|
|
Цитата shershen @ Как?, если это не секрет.. но уже решил проблему по другому |
Сообщ.
#15
,
|
|
|
GetTempFile
|
Сообщ.
#16
,
|
|
|
Цитата simsergey @ Как?, если это не секрет.. У меня есть главный процесс, который управляет этими дочерними процессами, вот он один генерит временные имена файлов и раздает дочерним. |
Сообщ.
#17
,
|
|
|
Цитата Fr0sT @ Если нужен совсем-совсем уникальный рэндом - то генери ГУИД. Не спасает при почти одновременной генерации - есть шанс словить два одинаковых значения. Помню, попался бложик одних чуваков, которые сделали первичные ключи в базе на GUID. В тестировании всё было ОК, а вот продакшн начал время от времени сваливаться в key constraint violation. После первой WTF-реакции был набросан синтетический тест, который и показал: параллельная генерация GUID может выдавать дубли. |