2009-08-09 2 views
1

Что такое хороший способ реализовать синглтон, который будет ограничен только потоком, который ищет его экземпляр? Есть ли идентификатор потока или что-то, что я могу использовать для этого? Я использую API-интерфейс Carbon threading, но вам придется реализовать это на окнах и чистом POSIX позже, поэтому любой метод оценен.Ограничение экземпляра Singleton для потока

+0

Это звучит как возможный дефект дизайна. Не могли бы вы объяснить свой контекст для использования этого механизма? –

+0

У меня есть графический движок, который использует singleton для доступа к некоторым своим основным функциям, и мне нужно иметь возможность создавать экземпляры нескольких экземпляров ядра для запуска в разных окнах, которые все работают на отдельных потоках. – toastie

ответ

1

В прошлом я использовал хэш-карту или индекс для хранения структур данных, которые являются потоками внутри одной глобальной потокобезопасной структуры данных. Например, если вы укажете идентификатор для каждого потока как возрастающее целое число, вы можете сохранить свою структуру данных в заранее выделенном массиве по индексу потока. Если вы используете идентификаторы потоков, которые предоставляются операционной системой или должны быть более гибкими, то безопасный поток HashMap или HashTable будет очень полезен.

Jacob

2

Как насчет чего-то подобного ThreadLocal в Java? Posix/Carbon должен иметь что-то ThreadLocal?

+0

Да, я не выглядел достаточно, прежде чем задавать вопрос. Кажется, в POSIX есть функция pthread_self, которая возвращает текущий идентификатор потока. http://opengroup.org/onlinepubs/007908775/xsh/pthread_self.html – toastie

0

Я не уверен, будет ли это ответ на ваш вопрос, но в моем классе Design Pattern, я узнал что-то вроде этого:

- (id) getInstance{ 
    @synchronized(self){ 
      if (mySingletonInstance == nil){ 
       @synchronized(self){ 
        mySingletonInstance = [[mySingleton alloc] init]; 
       } 
      } 
    } 
    return mySingletonInstance; 
} 

Хотя код в объективно- C, идея должна быть примерно такой же на другом языке, ИМХО.

1

Я хотел бы поместить указатель одиночного текста в любой локальный метод хранения потока в системе. Вы назвали несколько, и я не знаю правильных заклинаний для них, но большинство потоковых систем имеют какую-то концепцию локального хранилища потоков.

Если ваша система нитей не работает, И ваша система потоковой передачи имеет уникальный идентификатор потока, то хеш-таблица (с ключом по идентификатору потока), вероятно, будет вашим лучшим выбором.

0

Если вы счастливы с Pthreads, вы должны смотреть на

Это должно охватывать OSX и Linux (я не использовал Carbon, но я предполагаю, что он использует реальные потоки ОС и поэтому отлично играет с pthreads).

Windows, имеет ту же самую основную идею с разными названиями и немного другой интерфейс:

http://msdn.microsoft.com/en-us/library/ms686991.aspx

Это позволяет получить доступ к «одиночкам» (*) для потока только из этого потока, но звучит так, как вы хотите. Если вы хотите иметь доступ к объекту любого потока из любого другого потока, вам нужна структура, основанная на pthread_t и почти наверняка некоторая синхронизация. Вы получаете значения pthread_t (то есть идентификаторы потоков) от pthread_self или pthread_create.

(*) Если у вас есть один для каждого потока, это технически не одноэлементно ...

1

Мы используем класс, который хранит карту идентификатора потока к данным для реализации наших потоков локального хранилища. Кажется, что это работает очень хорошо, тогда экземпляр этого класса можно разместить везде, где требуется локальное хранилище потоков.Обычно клиенты используют экземпляр как статическое частное поле.

Вот грубый набросок кода

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(); 
    // ... 
} 

Это очень просто и работает на любой платформе, где вы можете получить идентификатор потока. Обратите внимание, что критическая секция используется только для возврата/создания ссылки, как только у вас есть ссылка, все вызовы находятся за пределами критической секции.