我可以使用pthreads分配每线程索引吗?

时间:2011-04-02 00:40:32

标签: multithreading thread-safety pthreads thread-local

我正在为我的项目(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索引?

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

为什么如此厌恶使用锁?解决竞争条件正是他们为......设计的......

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

答案 2 :(得分:0)

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

下面是一个示例HelloWorld,它创建N个线程,为每个线程分配0到N-1的索引。每个线程只做“hi”并给它的索引:

#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