2016-11-29 63 views
1

我正在考虑如何实现一个包含私有数据的类,这些私有数据将最终由多个线程通过方法调用进行修改。对于同步(使用Windows API),我计划使用一个对象,因为所有线程都将从同一个进程产生。从多个线程同步方法调用共享对象

鉴于以下设计,我有几个问题。

template <typename T> class Shareable 
{ 
private: 
    const LPCRITICAL_SECTION sync; //Can be read and used by multiple threads 
    T *data; 
public: 
    Shareable(LPCRITICAL_SECTION cs, unsigned elems) : sync{cs}, data{new T[elems]} { } 
    ~Shareable() { delete[] data; } 
    void sharedModify(unsigned index, T &datum) //<-- Can this be validly called 
    //by multiple threads with synchronization being implicit? 
    { 
     EnterCriticalSection(sync); 
     /* 
      The critical section of code involving reads & writes to 'data' 
     */ 
     LeaveCriticalSection(sync); 
    } 
}; 

// Somewhere else ... 

DWORD WINAPI ThreadProc(LPVOID lpParameter) 
{ 
    Shareable<ActualType> *ptr = static_cast<Shareable<ActualType>*>(lpParameter); 
    T copyable = /* initialization */; 
    ptr->sharedModify(validIndex, copyable); //<-- OK, synchronized? 
    return 0; 
} 

我看到它的方式,API调用将在当前线程的上下文中进行。也就是说,我认为这与我从指针中获取临界区对象并从ThreadProc()内调用API相同。但是,我担心如果该对象被创建并放置在主/初始线程中,那么API调用将会有些奇怪。

  1. sharedModify()称为同一对象上同时, 从多个线程,将所述同步是隐含的,在I中描述它上面的 方式吗?
  2. 我是否应该得到一个指向 临界区对象的指针并使用它?
  3. 是否还有其他一些 更适合这种情况的同步机制?

回答

1

sharedModify()是同一对象上称为同时,从多个线程,将所述同步是隐含的,在I中描述它上面的方法是什么?

从调用者的角度来看,是的。

我是否应该得到一个指向临界区对象的指针并使用它?

号其实,我建议给自己的临界区的Sharable对象所有权,而不是接受来自外部的一个(和拥抱RAII概念编写更安全的代码),例如:

template <typename T> 
class Shareable 
{ 
private: 
    CRITICAL_SECTION sync; 
    std::vector<T> data; 

    struct SyncLocker 
    { 
     CRITICAL_SECTION &sync; 
     SyncLocker(CRITICAL_SECTION &cs) : sync(cs) { EnterCriticalSection(&sync); } 
     ~SyncLocker() { LeaveCriticalSection(&sync); } 
    } 

public: 
    Shareable(unsigned elems) : data(elems) 
    { 
     InitializeCriticalSection(&sync); 
    } 

    Shareable(const Shareable&) = delete; 
    Shareable(Shareable&&) = delete; 

    ~Shareable() 
    { 
     { 
     SyncLocker lock(sync); 
     data.clear(); 
     } 
     DeleteCriticalSection(&sync); 
    } 

    void sharedModify(unsigned index, const T &datum) 
    { 
     SyncLocker lock(sync); 
     data[index] = datum; 
    } 

    Shareable& operator=(const Shareable&) = delete; 
    Shareable& operator=(Shareable&&) = delete; 
}; 

是否有一些更适合此场景的其他同步机制?

这取决于。多个线程会同时访问相同的索引吗?如果不是,那么根本就不需要关键部分。一个线程可以安全地访问一个索引,而另一个线程访问不同的索引。

如果多个线程需要同时访问同一个索引,那么关键部分可能仍然不是最佳选择。如果您只需要一次锁定阵列的部分,锁定整个阵列可能会是一个很大的瓶颈。诸如Interlocked API或Slim Read/Write锁之类的东西可能更有意义。这真的取决于你的线设计和你实际上想要保护的东西。

2

当sharedModify()被调用的相同的对象上同时,从多个线程,将所述同步是隐含的,在I中描述它上面的方法是什么?

这不是隐含的,它是明确的。只有CRITICAL_SECTION,一次只能有一个线程持有它。

我是否应该得到一个指向临界区对象的指针并使用它?

不。没有理由在这里使用指针。

是否有一些其他同步机制更适合此场景?

很难说没有看到更多的代码,但这绝对是“默认”解决方案。这就像一个单独链接的列表 - 你首先学习它,它总是有效的,但它并不总是最好的选择。

相关问题