2

我正在为我的项目(Linux、ICC、pthreads)优化一些工具,并希望对此技术有一些反馈,以便为线程分配唯一索引,因此我可以使用它来索引每个线程数据的数组。

旧技术使用基于 pthread id 的 std::map,但我想尽可能避免锁定和映射查找(它会产生大量开销)。

这是我的新技术:

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 索引?

4

3 回答 3

2

1)原子增量实际上会有所帮助,因为可能的竞争是两个线程读取并为自己分配相同的ID,因此确保增量(读取编号,加1,存储编号)以原子方式修复该竞争条件。在英特尔上,“lock; inc”可以解决问题,或者您的平台提供的任何东西(例如 Windows 的 InterlockedIncrement() )。

2)好吧,您实际上可以使整个信息线程本地化(“__thread static PerThreadInfo info;”),前提是您的唯一目标是能够轻松地以通用名称访问每个线程的数据。如果您确实希望它是一个全局可访问的数组,那么像使用 TLS 一样保存索引是一种非常直接且有效的方法。正如 Kromey 在他的帖子中所指出的,您还可以预先计算索引并在创建线程时将它们作为参数传递。

于 2011-04-02T10:09:49.397 回答
1

为什么这么讨厌使用锁?解决竞争条件正是他们的设计目的......

无论如何,您可以使用 pthread_create() 中的第四个参数将参数传递给线程的启动例程;这样,您可以使用主进程在启动线程时生成递增计数器,并在创建时将此计数器传递给每个线程,从而为每个线程提供唯一索引。

于 2011-04-02T00:49:50.210 回答
0

我知道你标记了这个 [pthreads],但你也提到了使用 std::map 的“旧技术”。这让我相信你正在用 C++ 编程。在 C++11 中,您有 std::thread,并且您可以在线程创建时通过普通函数参数将唯一索引(id)传递给您的线程。

下面是一个创建 N 个线程的 HelloWorld 示例,为每个线程分配一个从 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
于 2011-04-02T23:29:09.870 回答