什么是实现单例的好方法,该单例将仅限于寻找其实例的线程?是否有线程 ID 或我可以用来执行此操作的东西?我正在使用 Carbon 线程 API,但稍后也必须在 Windows 和纯 POSIX 上实现它,因此任何技术都值得赞赏。
6 回答
类似于 Java 中的 ThreadLocal 的东西怎么样?Posix/Carbon 应该有一些 ThreadLocal 对吗?
过去,我利用哈希图或索引来存储单个全局线程安全数据结构内的每个线程的数据结构。例如,如果您将每个线程的 id 作为递增整数提供,您可以将数据结构存储在线程索引处的预分配数组中。如果您正在利用操作系统提供的线程 ID 或需要更灵活,那么线程安全的 HashMap 或 HashTable 将非常方便。
雅各布
我想将单例指针放入系统的线程本地存储方法中。您已经命名了几个,我不知道它们的正确咒语,但大多数线程系统都有某种线程本地存储概念。
如果您的线程系统没有,并且您的线程系统确实具有唯一的线程标识符,那么哈希表(由线程 id 键入)可能是您最好的选择。
我们使用一个将线程 id 映射到数据的类来实现我们的线程本地存储。这似乎工作得很好,然后可以将此类的实例放置在您需要线程本地存储的任何地方。通常客户端使用实例作为静态私有字段。
这是代码的大致轮廓
template <class T>
struct ThreadLocal {
T & value()
{
LockGuard<CriticalSection> lock(m_cs);
std::map<int, T>::iterator itr = m_threadMap.find(Thread::getThreadID());
if(itr != m_threadMap.end())
return itr->second;
return m_threadMap.insert(
std::map<int, T>::value_type(BWThread::getThreadID(), T()))
.first->second;
}
CriticalSection m_cs;
std::map<int, T> m_threadMap;
};
然后将其用作
class A {
// ...
void doStuff();
private:
static ThreadLocal<Foo> threadLocalFoo;
};
ThreadLocal<Foo> A::threadLocalFoo;
void A::doStuff() {
// ...
threadLocalFoo.value().bar();
// ...
}
这很简单,适用于任何可以获取线程 ID 的平台。请注意,关键部分仅用于返回/创建引用,一旦您拥有引用,所有调用都在关键部分之外。
我不确定这是否能回答你的问题,但在我的设计模式课上,我学到了这样的东西:
- (id) getInstance{
@synchronized(self){
if (mySingletonInstance == nil){
@synchronized(self){
mySingletonInstance = [[mySingleton alloc] init];
}
}
}
return mySingletonInstance;
}
尽管代码是用 Objective-C 编写的,但在其他语言中应该是相同的,恕我直言。
如果你对 pthreads 很满意,你应该看看
pthread_key_create
pthread_setspecific
pthread_getspecific
这应该涵盖 OSX 和 linux(我没有使用过 Carbon,但我猜它使用真正的 OS 线程,因此可以很好地与 pthreads 配合使用)。
Windows 具有相同的基本思想,但名称不同,界面略有不同:
http://msdn.microsoft.com/en-us/library/ms686991.aspx
这允许您仅从该线程访问线程的“单例”(*),但听起来这就是您想要的。如果您希望能够从任何其他线程访问任何线程的对象,那么您需要一个以 a 为键的结构pthread_t
,并且几乎可以肯定是一些同步。您从或获取pthread_t
值(即线程 ID)。pthread_self
pthread_create
(*) 如果每个线程都有一个,从技术上讲,它不是单例...