портативная печать и сравнение pthread_t - PullRequest
1 голос
/ 21 января 2011

Что мне действительно нужно, так это переносимое сравнение и печать идентификаторов * nix pthread (pthread_t).Функция pthread_equal существует для сравнения двух идентификаторов потоков на равенство, однако невозможно сравнить их с операторами <<=> => (я имею в виду, конечно, переносимые), потому что в некоторых реализациях pthread_t является указателем на структуру.Поэтому я нашел решение, которым хотел бы поделиться и обсудить его переносимость.

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

template <typename T, bool A = is_arithmetic<T>::value>
struct hash
{
    static unsigned long calculate(T thread_id)
    {
        return hash<T*, A>::calculate(&thread_id);
    }
};

template <typename T>
struct hash<T*, false>
{
    static unsigned long calculate(T* thread_id)
    {
        std::size_t hash = 0;
        if (char* data = reinterpret_cast<char*>(thread_id))
        {
            for (int i = 0; i < sizeof(T); ++i)
            {
                hash = (hash << 6) ^ (hash >> 26) ^ data[i];
            }
        }
        return hash;
    }
};

template <typename T>
struct hash<T, true>
{
    static unsigned long calculate(T thread_id)
    {
        return static_cast<unsigned long>(thread_id);
    }
};

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

pthread_equal(tid1, tid2);

, но для оператора <мы используем хеш для сравнения </p>

hash<pthread_t>::calculate(tid1) < hash<pthread_t>::calculate(tid2)

Так что здесь

, если pthread_t реализован как указатель, тогда мы вычислим хеш для указанного объекта.

Если это арифметический тип, то мы просто попытаемся привести его к типу без знака.

Если он реализован какструктура - мы рассчитаем хеш для самого объекта структуры.

Значение хеша будет использоваться только для оператора без вывода и вывода идентификатора потока.

Что вы думаете об этом?Насколько портативно это решение и есть ли что-нибудь лучше этого?

Спасибо всем заранее.

Ответы [ 3 ]

1 голос
/ 03 июля 2013

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

В дополнение к этому, pthread_t, включая скалярныеpthread_t, может содержать биты заполнения, которые будут вводить «шум», который влияет на результат хеширования.В настоящее время не существует универсально переносимого способа сравнения pthread_t на уровне пользователя.

Фактически, pthread_equal в системах, где pthread_t является указателем, может возвращать равенство, даже если два аргумента фактически ссылаются на разные потоки, напримерПоток может завершиться, и может быть создан новый поток с тем же значением указателя и, следовательно, значением pthread_t.

Метод сопоставленного уникального идентификатора будет работать при условии, что вам никогда не потребуется выполнять обратный поиск, поскольку карта может иметь значение 1:п.Карта также становится очень большой, если вы постоянно выходите и создаете темы.

1 голос
/ 21 января 2011

Вместо того, чтобы пытаться сравнивать pthread_t, вы можете просто инкапсулировать создание потока и добавить новый поток в map<some_id, pthread_t>, где идентификатор генерируется и является уникальным. Тогда вы всегда обращаетесь к темам по идентификатору и можете упорядочивать, сортировать, сравнивать их по своему усмотрению.

0 голосов
/ 21 января 2011

Тип данных pthread_t не является стандартным, поэтому я предполагаю, что предоставляется pthread_compare().

В моем приложении я также отображаю pthread_t на некоторый уникальный идентификатор, как предложил Марк.Смотри здесь

...