Могу ли я назначить индекс для каждого потока, используя pthreads? - PullRequest
1 голос
/ 02 апреля 2011

Я оптимизирую некоторые инструментальные средства для своего проекта (Linux, ICC, pthreads) и хотел бы получить некоторые отзывы об этой технике, чтобы назначить уникальный индекс потоку, чтобы я мог использовать его для индексации в массив перданные потока.

В старой технике используется std :: map на основе идентификатора pthread, но я бы хотел избежать блокировок и поиска карты, если это возможно (это создает значительные накладные расходы).

Вот моя новая техника:

static PerThreadInfo info[MAX_THREADS]; // shared, each index is per thread

// Allow each thread a unique sequential index, used for indexing into per
// thread data.
1:static size_t GetThreadIndex()
2:{
3:   static size_t threadCount = 0;
4:   __thread static size_t myThreadIndex = threadCount++;
5:   return myThreadIndex;
6:}

позже в коде:

// add some info per thread, so it can be aggregated globally
info[ GetThreadIndex() ] = MyNewInfo();

Итак:

1) Похоже, что линия 4 может быть условием гонки.если два потока были созданы в одно и то же время.Если так - как я могу избежать этого (желательно без замков)?Я не вижу, как атомарный прирост мог бы помочь здесь.

2) Есть ли лучший способ как-нибудь создать индекс для каждого потока?Может быть, как-то предварительно сгенерировав индекс TLS при создании потока?

Ответы [ 3 ]

2 голосов
/ 02 апреля 2011

1) Атомный инкремент здесь действительно помог бы, так как возможная гонка - это два потока, считывающих и присваивающих один и тот же идентификатор, поэтому уверенность в том, что приращение (число чтения, добавление 1, номер магазина) атомарно исправляет это состояние гонки,В Intel "lock; inc" справился бы с задачей, или с тем, что предлагает ваша платформа (например, InterlockedIncrement () для Windows).

2) Ну, на самом деле вы могли бы сделать всю информационную нить локальной ("__thread static PerThreadInfo info;"), при условии, что ваша единственная цель - получить доступ к данным для каждого потока легко и под общим именем.Если вы действительно хотите, чтобы это был глобально доступный массив, то сохранение индекса, как вы делаете это с использованием TLS, является очень простым и эффективным способом сделать это.Вы также можете предварительно вычислить индексы и передать их в качестве аргументов при создании потока, как отметил Кромей в своем посте.

1 голос
/ 02 апреля 2011

Почему так против использования замков?Решение условий гонки - это именно то, для чего они предназначены ...

В любом случае, вы можете использовать 4-й аргумент в pthread_create () для передачи аргумента в процедуру запуска ваших потоков;таким образом, вы можете использовать ваш мастер-процесс для генерации увеличивающегося счетчика, когда он запускает потоки, и передавать этот счетчик в каждый поток по мере его создания, давая вам уникальный индекс для каждого потока.

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

Я знаю, что вы пометили это [pthreads], но вы также упомянули «старый метод» использования std :: map.Это наводит меня на мысль, что вы программируете на C ++.В C ++ 11 у вас есть std :: thread, и вы можете передавать уникальные индексы (идентификаторы) своим потокам во время создания потока через обычный параметр функции.

Ниже приведен пример HelloWorld, который создает N потоковприсваивая каждому индекс от 0 до N-1.Каждая нить ничего не делает, только говорит «привет» и дает свой индекс:

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>

inline void sub_print() {}

template <class A0, class ...Args>
void
sub_print(const A0& a0, const Args& ...args)
{
    std::cout << a0;
    sub_print(args...);
}

std::mutex&
cout_mut()
{
    static std::mutex m;
    return m;
}

template <class ...Args>
void
print(const Args& ...args)
{
    std::lock_guard<std::mutex> _(cout_mut());
    sub_print(args...);
}

void f(int id)
{
    print("This is thread ", id, "\n");
}

int main()
{
    const int N = 10;
    std::vector<std::thread> threads;
    for (int i = 0; i < N; ++i)
        threads.push_back(std::thread(f, i));
    for (auto i = threads.begin(), e = threads.end(); i != e; ++i)
        i->join();
}

Мой вывод:

This is thread 0
This is thread 1
This is thread 4
This is thread 3
This is thread 5
This is thread 7
This is thread 6
This is thread 2
This is thread 9
This is thread 8
...