Ограничение экземпляра Singleton потоком - PullRequest
1 голос
/ 09 августа 2009

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

Ответы [ 6 ]

2 голосов
/ 09 августа 2009

Как насчет чего-то похожего на ThreadLocal в Java? У Posix / Carbon должно быть что-то, что ThreadLocal верно?

1 голос
/ 10 августа 2009

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

Вот примерный набросок кода

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

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

1 голос
/ 09 августа 2009

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

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

1 голос
/ 09 августа 2009

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

Jacob

0 голосов
/ 09 августа 2009

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

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

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

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

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

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

0 голосов
/ 09 августа 2009

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

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

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

...