Поиск наименьшего неиспользуемого числа является очень распространенной операцией в ядрах UNIX, как и каждое open
/ socket
/ etc. Предполагается, что syscall связывается с самым низким неиспользуемым номером FD.
В Linux алгоритм в fs/file.c
& shy; # alloc_fd
:
- отслеживайте
next_fd
, низкий уровень воды - это не обязательно 100% точность
- всякий раз, когда освобождается ФД,
next_fd = min(fd, next_fd)
- чтобы выделить FD, начните поиск растрового изображения, начиная с
next_fd
- lib/find_next_bit.c
& shy; # find_next_zero_bit
линейно, но все еще очень быстро, потому что требуется BITS_PER_LONG
шагов по время
- после выделения FD,
next_fd = fd + 1
FreeBSD sys/kern/kern_descrip.c
& shy; # fdalloc
следует той же идее: начните с int fd_freefile; /* approx. next free file */
и ищите растровое изображение вверх.
Однако все они работают в предположении, что в большинстве процессов открыто мало FD, а в очень, очень немногих - тысячи. Если числа будут намного выше, с редкими дырками, общее решение (насколько я видел) будет
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int high_water_mark = 0;
vector<int> unused_numbers = vector<int>();
int get_new_number() {
if (used_numbers.empty())
return high_water_mark++;
pop_heap(unused_numbers.begin(), unused_numbers.end(), greater<int>());
return unused_numbers.pop_back();
}
void recycle_number(int number) {
unused_numbers.push_back(number);
push_heap(unused_numbers.begin(), unused_numbers.end(), greater<int>());
}
(непроверенный код ... идея такова: удерживайте отметку уровня воды; попытайтесь украсть отметку unused
ниже отметки уровня воды или иным способом - отметку уровня воды выше; верните значение unused
)
и если вы предполагаете, что используемые числа будут редкими, то решение Дмитрия имеет больше смысла.