Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Singleton в нескольких потоках, как? 
V
    Опции темы
azesmcar
Дата 24.3.2009, 13:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Добрый день,

Есть класс SomeThread который делает конкретную задачу..обьектов этого класса - несколько. Каждый обьект имеет свое сойденение с базой данных и в принципе абсолютно изолирован (т.е. никаких глобальных данных и тому подобного, каждый обьект оперирует со своими локальными данными). Но как понимаете весь функционал не написан в модуле SomeThread, а он использует некие вспомогательные классы SystemUser, UserActionHandler и тому подобное. Вопрос в том что в каждом модуле мне нужно подключение к базе данных которое создано в классе SomeThread, а передавать его в каждый модуль, как-то некрасиво. Можно конечно создать синглтон, но..это потоки, т.е. на каждый поток должно быть свое подключение. Как это можно сделать? Было бы красиво что-то вроде

Код

class SystemUser
{
public:
   bool Logon(const std::string login, const std::string password) {
      ThreadContext<тут что-то передать>::DBConnection()->Query( ... );
   }
}


но вот как это реализовать? 
PM   Вверх
Lazin
Дата 24.3.2009, 14:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



например, с помощью boost::call_once
PM MAIL Skype GTalk   Вверх
azesmcar
Дата 24.3.2009, 14:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата

например, с помощью boost::call_once 


а без буста? меня больше принцип реализации интересует
PM   Вверх
jonie
Дата 24.3.2009, 22:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 15
Всего: 118



если я правильно понял задачу, то на каждый поток у вас свое подключение.
почему нельзя сделать в том классе что вы привели static map<threadId, connectionPtr> connections и при каждом обращении из конкретного потока (его id мы всегда сможем узнать) в каждой функции либо брать кешированное соединение либо создавать, пихать в кеш и использовать ?

замечания:
1) map это НЕ std::map ! т.к. последний не потокобезопасен (хотя можно доступ к нему сделать таковым)
2) кешировать соединение не очень хорошо (точнее очень нехорошо). могут быть проблемы. все зависит от задачи.
3) конечно нужна функции "отключится от объекта"


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
Cтpaнник
Дата 24.3.2009, 23:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 53
Регистрация: 12.10.2008
Где: Россия, Санкт-Пет ербург

Репутация: нет
Всего: нет



Если дело происходит в Windows и кроссплатформенность кода не нужна, то имеет смысл посмотреть в сторону платформенно-специфичных средств (а именно, в Win это TLS). 
Например, в MSVC++ есть конструкция __declspec(thread) <тип данных> <имя переменной>; - таким образом создается экземпляр переменной, специфичный для вызывающего потока. Это позволит разделить connectionPtr и за каждым потоком закрепить свой экземпляр оного. Если применить еще и идиому RTTI, то, возможно, удастся решить и проблемы с "зависшими" или незакрытыми соединениями.... 
PM MAIL   Вверх
Lazin
Дата 24.3.2009, 23:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



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

Добавлено через 6 минут и 1 секунду
Цитата(Cтpaнник @  24.3.2009,  23:13 Найти цитируемый пост)
Например, в MSVC++ есть конструкция __declspec(thread) <тип данных> <имя переменной>; - таким образом создается экземпляр переменной, специфичный для вызывающего потока. Это позволит разделить connectionPtr и за каждым потоком закрепить свой экземпляр оного. Если применить еще и идиому RTTI, то, возможно, удастся решить и проблемы с "зависшими" или незакрытыми соединениями....  

только если ты не пишешь разделяемую библиотеку smile 
PM MAIL Skype GTalk   Вверх
azesmcar
Дата 25.3.2009, 06:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата

если я правильно понял задачу, то на каждый поток у вас свое подключение.


Абсолютно верно.
Цитата

почему нельзя сделать в том классе что вы привели static map<threadId, connectionPtr> connections и при каждом обращении из конкретного потока (его id мы всегда сможем узнать) в каждой функции либо брать кешированное соединение либо создавать, пихать в кеш и использовать ?


так и думал сделать, но
Цитата

1) map это НЕ std::map ! т.к. последний не потокобезопасен (хотя можно доступ к нему сделать таковым)

если учесть что в этот мап значения добавляются всего один раз в начале одним потоком, а потом ТОЛЬКО читают из него методом find, могут ли быть проблемы..со вчерашнего дня об этом и думаю.
Цитата

Если дело происходит в Windows и кроссплатформенность кода не нужна, то имеет смысл посмотреть в сторону платформенно-специфичных средств (а именно, в Win это TLS). 


нет, мне скорее нужно под линукс..но код кроссплатформенный.
PM   Вверх
jonie
Дата 25.3.2009, 07:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 15
Всего: 118



Цитата

если учесть что в этот мап значения добавляются всего один раз в начале одним потоком, а потом ТОЛЬКО читают из него методом find, могут ли быть проблемы..со вчерашнего дня об этом и думаю.
сама карта, конечно, ничего делать не будет "просто так", но т.к. класс не потокобезопасен, потоковые операции все же стоит производить атомарно - "малоли чего".


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
azesmcar
Дата 27.3.2009, 08:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата

сама карта, конечно, ничего делать не будет "просто так", но т.к. класс не потокобезопасен, потоковые операции все же стоит производить атомарно - "малоли чего".


ну это понятно, но тут есть что-то что мне не нравится, фактически потоки, у которых свое сойденение к базе должны ждать, хоть и недолго, но все же ждать пока поиск закончится..не нравится мне это. Может стоит сменить архитектуру пока не поздно? Но другого ничего не приходит на ум. Не писать же все в одном модуле? Никто не сталкивался с подобным что ли? Синглтон очень нужная в нашей жизни штука, а многопоточное приложение в наше время не редкость..
PM   Вверх
azesmcar
Дата 27.3.2009, 09:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Все!!! управился, привожу решение кому интересно.
В виндоуз есть такая штука как TLS (Thread Local Storage). Вещь полезная и полностью решающая данную задачу. В никсах она добавлена как патч, но это было давно и в принципе на данный момент вы вряд ли найдете систему которая не поддерживает TLS.
Код

#ifdef WIN32
#define TLS __declspec( thread ) static
#else
#include <pthread.h>
#define TLS __thread static
#endif


вот и все..обявляем статические переменные как
Код

void ThreadProc(void* lpParameter)
{
    TLS int p = 0;
}


и наслаждаемся Thread Scope Static переменными!

Всем спасибо.
PM   Вверх
Lazin
Дата 27.3.2009, 11:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(azesmcar @  27.3.2009,  09:50 Найти цитируемый пост)
__declspec( thread )

нельзя использовать в dll, если ты будет загружать dll динамически, то будут проблемы

Добавлено через 7 минут и 7 секунд
workaround
Код

template <typename T>
class ThreadLocal
{
private:
    DWORD threadLocalIndex;

    ThreadLocal(ThreadLocal const&);

    T *GetPointer(void)
    {
        return static_cast<T*>(::TlsGetValue(threadLocalIndex));
    }

    void SetPointer(T *value)
    {
        ::TlsSetValue(threadLocalIndex, static_cast<void*>(value));
    }
public:
    void SetValue(const T &value)
    {
        T* currentPointer = GetPointer();
        if (currentPointer == NULL)
        {
            SetPointer(new T(value));
        }
        else
        {
            *currentPointer = value;
        }
    }

    T &GetValue()
    {
        T* currentPointer = GetPointer();
        if (currentPointer == NULL)
        {
            SetPointer(new T());
        }
        return *GetPointer();
    }

    operator T() 
    {
        return GetValue();
    }

    ThreadLocal<T>& operator = (const T& value)
    {
        SetValue(value);
        return *this;
    }

    void DeleteValue()
    {
        T* currentPointer = GetPointer();
        if (currentPointer != NULL)
        {
            delete currentPointer;
            SetPointer(NULL);
        }
    }

    ThreadLocal(const T& value)
    {
        threadLocalIndex = ::TlsAlloc();
        SetValue(value);
    }

    ThreadLocal()
    {
        threadLocalIndex = ::TlsAlloc();
    }

    ~ThreadLocal()
    {
        DeleteValue();
        ::TlsFree(threadLocalIndex);
    }
};

PM MAIL Skype GTalk   Вверх
azesmcar
Дата 27.3.2009, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата

нельзя использовать в dll, если ты будет загружать dll динамически, то будут проблемы


я и не собираюсь, но спасибо за информацию, почитаю про это.
PM   Вверх
0xDX
Дата 28.3.2009, 03:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 6.2.2009

Репутация: нет
Всего: нет



Делай селектор,

А в селекторе возвращаемые объекты вычисляй по ID потока

Что то вроде
switch(IdThread)
{
case First:
       retunrn array_object[1];
case Second:
       retunrn array_object[1];
default:
return 0;
}

Весь код я не писал, если надо то скажи.
PM MAIL   Вверх
azesmcar
Дата 28.3.2009, 09:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



0xDX  smile 

1. Количество потоков - динамическое, еслиб я точно знал их количество - я бы придумал решения и покрасивей..хотя бы с шаблонами.
2. Откуда ты возьмешь First и Second? Это не константные значения. ИД потока изменяется при каждом запуске программы.
3. Чем тебе не нравится мое решение? Думаешь свитч красивее?
PM   Вверх
0xDX
Дата 30.3.2009, 00:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 6.2.2009

Репутация: нет
Всего: нет



azesmcar  на винд работать не будет.

Цитата

1. Количество потоков - динамическое, еслиб я точно знал их количество - я бы придумал решения и покрасивей..хотя бы с шаблонами.
2. Откуда ты возьмешь First и Second? Это не константные значения. ИД потока изменяется при каждом запуске программы.


Ассоциативный контейнер полечит.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1084 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.