2

每个线程可以使用“插入”函数将对象插入容器(最多一次)。此后,线程可能会尝试使用“get”函数访问该对象。因此,当被同一线程使用时,'insert' 和 'get' 之间没有竞争。但是,当另一个线程调用“get”时,另一个线程可能会尝试插入自己的对象

我需要一个容器,这种情况不需要任何同步方法。

执行之间的线程数可能会有很大差异。

class Object;
class Container<Object>;

Container<Object> g_container;

void insert(int threadId)
{
    ScopedLock<Mutex> lock(insertMutex);
    Object obj;
    g_container[threadId] = obj;
}

Object get(int threadId)
{
    return g_container[threadId];
}
4

3 回答 3

1

您可以使用容器指针向量。每个线程管理自己的容器实例,并将其注册到容器指针数组中。

template <typename T>
struct Container {
    Mutex insertMutex;
    ContainerType<T> container;
    int index;
    void insert (T &obj) {
        ScopedLock<Mutex> lock(insertMutex);
        container.insert(obj);
    }
    T get () {
        return *container.begin();
    }
    void register_container () {
        if (index != 0) return;
        if (counter == MAX_THREADS) throw 0;
        index = ++counter;
        ScopedLock<Mutex> lock(registerMutex);
        containers.push_back(this);
    }
    static std::vector<Container *> containers;
    static Atomic<int> counter;
    static Mutex registerMutex;
};

template <typename T>
std::vector<Container<T> *> Container<T>::containers;

template <typename T>
Atomic<int> Container<T>::counter;

template <typename T>
Mutex Container<T>::registerMutex;

现在,您可以遍历Container<T>::containers以访问所有容器。

于 2012-07-03T06:58:56.547 回答
1

您正在寻找的东西通常称为“无锁数据结构”。

我理解你为什么认为你需要一个无锁容器,但我几乎可以向你保证你不需要。他们通常比他们的价值更麻烦。您应该只有一个互斥锁来管理对普通容器的所有访问。锁定要插入容器的互斥锁。锁定互斥体以从容器中删除。并在读取(或迭代)容器之前锁定互斥锁。

以下是 C++ 标准委员会主席 Herb Sutter 的一些有益讨论:

http://www.drdobbs.com/cpp/lock-free-code-a-false-sense-of-security/210600279

于 2012-07-03T07:21:40.277 回答
1

+1 詹姆斯布洛克。

但这听起来更像是您希望每个线程都有一个容器,但是是互斥的,并且锁定/解锁互斥锁很便宜,因为 99.9% 的时间操作第一次成功。但是“主”线程确实有能力在检查其他线程时偶尔暂停它们。

如果每个线程只有一个对象,容器就会消失。只需锁定对象。不要担心锁定的成本,除非它是一个经过验证的性能问题。在这种情况下,问题不在于移除锁,而仅仅是减少它们的使用频率。所以保持对象锁定,每百次左右才解锁一次。必要时结合条件变量。

于 2012-07-03T07:46:25.183 回答