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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> потокобезопасный синглтон 
V
    Опции темы
JanryMayers
Дата 9.8.2011, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 71
Регистрация: 11.6.2009
Где: Украина, г. Киев

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



 Доброго времени, всем)

Запутался.

Вопрос такой: как реализовать в моем случае потокобезопасный синглтон либо нужен ли он в моем случае вообще и как обойтись без него?

Задача: Клиенты отправляют запросы

Код

void Client::sendRequest()
{
    TDATA request = createRequest();
    QueueWithPriority<BYTE, TDATA>::addRequest(request);
}


они добавляются в мапу очередей, вот .h очереди

Код

#    pragma once
#    include <map>
#    include <queue>
#    include <boost/thread/mutex.hpp>


template <class priority, class TypeData>
class QueueWithPriority
{
public:

    static QueueWithPriority* getInstance()
    {
        if(instance==NULL)
        {
            instance = new QueueWithPriority;
        }
        return instance;
    }

    static void addRequest(TypeData);

private:
    QueueWithPriority();
    ~QueueWithPriority();

private:

    static QueueWithPriority*                    instance;
    std::map<priority, std::queue<TypeData>>    queueWithPriority;
    static boost::mutex                            _mutex;

};

template <class priority, class TypeData>
QueueWithPriority<priority, TypeData>::QueueWithPriority()
{}

template <class priority, class TypeData>
QueueWithPriority<priority, TypeData>::~QueueWithPriority()
{}

template <class priority, class TypeData>
QueueWithPriority<priority, TypeData>* QueueWithPriority<priority, TypeData>::instance=NULL;

template <class priority, class TypeData>
void QueueWithPriority<priority, TypeData>::addRequest(TypeData request)
{

        // вот тут не знаю как это обойти ---
    instance = QueueWithPriority::getInstance();

    boost::mutex::scoped_lock lock(instance->_mutex);
        //  ---

    priority _priority = request.cPriority;

    std::map<priority, std::queue<TypeData>>::iterator queueIterator = instance->queueWithPriority.find(_priority);

    if (queueIterator == instance->queueWithPriority.end())
    {
        //добавление в дерево очередей
    }

    //добавление запроса в конец очереди
    
}


собственно проблема в том что клиент отправляет запрос... я сделал очердь шаблоном, что бы данные туда могли поступать различного типа, соответственно о типе данных знает только клиент и сервер( вот тут тоже не уверен) когда пытается их изъять и обработать.
По этому клиент отправляя запрос создает класс QueueWithPriority с нужными списком аргументов для шаблона.

Вообщем помогите как тут правильно сделать?
ещё нашел интересную статью, там ход рассуждений сводится к

Код

static volatile singleton* instance() {
   singleton* temp = inst;
   read_memory_barrier();
   if (inst == 0) {
      if (inst == 0) {
         temp = new singleton();
         write_memory_barrier();
         inst = temp;
      }
   }
   return inst;
}


не знаю подойдет он к моей задаче или нет?

вот часть main.cpp
Код

int main(int argv, char *argc[])
{
    input input_command;
    while(!input_command.verify()){
        input_command.input_cmd();
    }

    size_t clientCount = input_command.getClientCount();

    std::vector<boost::shared_ptr<Client>> clients;
    std::vector<Client*>::const_iterator    thr_it;

    for(size_t i = 0; i<clientCount; i++){
        DWORD clientID = static_cast<DWORD>(i);
        clients.push_back(boost::shared_ptr<Client>(new Client(clientID)));
    }
}

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


uploading...
****


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

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



Цитата(JanryMayers @  9.8.2011,  15:13 Найти цитируемый пост)
ещё нашел интересную статью, там ход рассуждений сводится к

это рассуждения о реализации DCLP сводяться к этому, а решение проблемы сводиться к
Цитата

boost/std::call_once

он как раз создан для этого.
а вообще, действительно ли тебе нужна "ленивая инициализация"?

PM   Вверх
JanryMayers
Дата 9.8.2011, 15:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 71
Регистрация: 11.6.2009
Где: Украина, г. Киев

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



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

Цитата

Цитата

boost/std::call_once

он как раз создан для этого.


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


uploading...
****


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

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



Цитата(JanryMayers @  9.8.2011,  15:58 Найти цитируемый пост)
не уверен..., просто предполагаю что задачу нужно решать так

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

Цитата(JanryMayers @  9.8.2011,  15:58 Найти цитируемый пост)
можете показать на примере 

Да, конечно.
Код

class singleton: private boost::noncopyable
{
public:
    static singleton* instance()
    {
        boost::call_once(init, flag);
        return object.get();
    }
private:
     static void init()
     {
         object.reset(new singleton());
     }
private:
     static boost::scoped_ptr<singleton> object;
     static boost::once_flag flag;
};

boost::scoped_ptr<singleton> singleton::object(0);
boost::once_flag singleton::flag = BOOST_ONCE_INIT;


Это сообщение отредактировал(а) azesmcar - 9.8.2011, 21:06
PM   Вверх
JanryMayers
Дата 9.8.2011, 22:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 71
Регистрация: 11.6.2009
Где: Украина, г. Киев

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



спасибо за пример.

на счет синглтона... я решил сделать так

Код

#    pragma once
#    include <map>
#    include <queue>
#    include <boost/thread/mutex.hpp>
#    include <boost/thread/once.hpp>
//#    include <boost/call>


template <class priority, class TypeData>
class QueueWithPriority
{
public:

    static void initialize()
    {
        instance = new QueueWithPriority;
    }

    static QueueWithPriority* getInstance()
    {
        if(instance==NULL)
        {
            instance = new QueueWithPriority;
        }
        return instance;
    }

    static void addRequest(TypeData);



private:
    QueueWithPriority();
    ~QueueWithPriority();

private:

    static QueueWithPriority*                instance;
    std::map<priority, std::queue<TypeData>>    queueWithPriority;
    static boost::mutex                            _mutex;    

};

template <class priority, class TypeData>
QueueWithPriority<priority, TypeData>::QueueWithPriority()
{}

template <class priority, class TypeData>
QueueWithPriority<priority, TypeData>::~QueueWithPriority()
{}

template <class priority, class TypeData>
QueueWithPriority<priority, TypeData>* QueueWithPriority<priority, TypeData>::instance=NULL;

template <class priority, class TypeData>
void QueueWithPriority<priority, TypeData>::addRequest(TypeData request)
{

    boost::mutex::scoped_lock lock(_mutex);

    priority _priority = request.cPriority;

    std::map<priority, std::queue<TypeData>>::iterator queueIterator = instance->queueWithPriority.find(_priority); //будет ли в этом месте instance работать корректно?

    
}


вот, а в main.cpp
Код

#    include "Client.h"
#    include "QueueWithPriority.h"

int main(int argv, char *argc[])
{
    input input_command;
    while(!input_command.verify()){
        input_command.input_cmd();
    }

    size_t clientCount = input_command.getClientCount();

    QueueWithPriority<BYTE, TDATA>::initialize();

    std::vector<boost::shared_ptr<Client>> clients;
    std::vector<Client*>::const_iterator    thr_it;

    for(size_t i = 0; i<clientCount; i++){
        DWORD clientID = static_cast<DWORD>(i);
        clients.push_back(boost::shared_ptr<Client>(new Client(clientID)));
    }

что скажете на этот счет?
думаю после этого все потоки которые будут вызывать getInstance будут получать ссылку, на существующий объект.

при попытке сбилдить 
выдает одну ошибку... которую не могу победить, есть мысли?

1>Client.obj : error LNK2001: unresolved external symbol "public: static class boost::mutex QueueWithPriority<unsigned char,struct tagTDATA>::_mutex" (?_mutex@?$QueueWithPriority@EUtagTDATA@@@@2Vmutex@boost@@A)
1>F:\Projects\TestQWP_Console\Debug\TestQWP_Console.exe : fatal error LNK1120: 1 unresolved externals
PM MAIL   Вверх
Qu1nt
Дата 10.8.2011, 01:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Код

struct Foo
{
    static Foo& instance()
    {
        static Foo instance;
        return instance;
    }
};

Потокобезопасный в С++0x.
PM MAIL   Вверх
JanryMayers
Дата 10.8.2011, 04:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 71
Регистрация: 11.6.2009
Где: Украина, г. Киев

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



Qu1nt, а можешь описать на моем примере?


 у меня получается так

Код

    static QueueWithPriority& instance()
    {
            static QueueWithPriority instance;
            return instance;
    }


а когда я вызываю вот этот участок кода

Код

template <class priority, class TypeData>
void QueueWithPriority<priority, TypeData>::addRequest(TypeData request)
{
    boost::mutex::scoped_lock lock( instance()._mutex );

    priority _priority = request.cPriority;

    std::map<priority, std::queue<TypeData>>::iterator queueIterator = instance().queueWithPriority.find(_priority);

    if (queueIterator == instance().queueWithPriority.end())
    {
        std::queue<TypeData> emptyQueue;
        instance().queueWithPriority.insert(std::pair<priority, std::queue<TypeData>>(_priority, emptyQueue));
        queueIterator = instance().queueWithPriority.find(_priority);
    }

    queueIterator->second.push(request);
    
}


queueWithPriority - не определено, то есть через watch там error symbols not found

Что не так?
PM MAIL   Вверх
JanryMayers
Дата 11.8.2011, 03:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 71
Регистрация: 11.6.2009
Где: Украина, г. Киев

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



Собрал все в кучу)

Господа) просьба принять на проверку)... 

Может можна как то упростить? или укоротить такие длинные надписи как вот эта

std::map<priority, std::queue<TypeData>>::iterator queueIterator = instance()->queueWithPriority.find(_priority);

Код

template <typename priority, typename TypeData>
class QueueWithPriority: private boost::noncopyable
{
public:
    static QueueWithPriority* instance()
    {
        boost::call_once(init, flag);
        return object.get();
    }

    static void addRequest(TypeData);
    static TypeData* extractRequest();

private:
    static void init()
    {
        object.reset(new QueueWithPriority());
    }
private:
    static boost::scoped_ptr<QueueWithPriority> object;
    static boost::once_flag flag;
    TypeData* requestExtract;
    std::map<priority, std::queue<TypeData>>    queueWithPriority;
    boost::mutex                                _mutex;
    QueueWithPriority*                            _instance;
};

template <typename priority, typename TypeData>
boost::scoped_ptr<QueueWithPriority<priority, TypeData>> QueueWithPriority<priority, TypeData>::object(0);

template <typename priority, typename TypeData>
boost::once_flag QueueWithPriority<priority, TypeData>::flag = BOOST_ONCE_INIT;

template <typename priority, typename TypeData>
void QueueWithPriority<priority, TypeData>::addRequest(TypeData request)
{

    boost::mutex::scoped_lock lock( instance()->_mutex );

    priority _priority = request.cPriority;

    std::map<priority, std::queue<TypeData>>::iterator queueIterator = instance()->queueWithPriority.find(_priority);

    if (queueIterator == instance()->queueWithPriority.end())
    {
        std::queue<TypeData> emptyQueue;
        instance()->queueWithPriority.insert(std::pair<priority, std::queue<TypeData>>(_priority, emptyQueue));
        queueIterator = instance()->queueWithPriority.find(_priority);
    }

    queueIterator->second.push(request);
}

template <typename priority, typename TypeData>
TypeData* QueueWithPriority<priority, TypeData>::extractRequest()
{

    boost::mutex::scoped_lock lock( instance()->_mutex );

    instance()->requestExtract = NULL;

    std::cout<<instance()->requestExtract<< "\n";

    if (instance()->queueWithPriority.empty())
    {
        std::cout<<"Queue is Empty!!!\n";
        return NULL;
    }

    std::map<priority, std::queue<TypeData>>::iterator queueIterator = instance()->queueWithPriority.begin();

    instance()->requestExtract = &queueIterator->second.back();

    queueIterator->second.pop();

    if (queueIterator->second.empty())
    {
        instance()->queueWithPriority.erase(queueIterator);
    }

    return instance()->requestExtract;
}


Это сообщение отредактировал(а) JanryMayers - 11.8.2011, 04:03
PM MAIL   Вверх
borisbn
Дата 11.8.2011, 08:13 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

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



Цитата(JanryMayers @  11.8.2011,  03:45 Найти цитируемый пост)
Может можна как то упростить? или укоротить такие длинные надписи как вот эта
std::map<priority, std::queue<TypeData>>::iterator queueIterator = instance()->queueWithPriority.find(_priority);

целых два варианта
1.
Код

typedef std::queue<TypeData> DataQueue;
typedef std::map<priority, DataQueue > PriorityMap;
PriorityMap::iterator = ...

2. (при наличие C++0x)
Код

auto queueIterator = instance()->queueWithPriority.find(_priority);


а ещё лучше их объединить: сделать typedef и использовать auto smile


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
JanryMayers
Дата 13.8.2011, 02:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 71
Регистрация: 11.6.2009
Где: Украина, г. Киев

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



Да тут ещё проблемка возникла

с функцией extract

Код

    template <typename priority, typename TypeData>
    TypeData* QueueWithPriority<priority, TypeData>::extractRequest()
    {

        boost::mutex::scoped_lock lock( instance()->_mutex );

        if (instance()->queueWithPriority.empty())
        {
            std::cout<<"Queue is Empty!!!\n";
            return NULL;
        }

        instance()->requestExtract = new TypeData();

        PriorityMap::iterator queueIterator = instance()->queueWithPriority.begin();

                // присвоили значение 
        instance()->requestExtract = &queueIterator->second.back();

        queueIterator->second.pop();

        if (queueIterator->second.empty())
        {
                // удалили значение на которое ссылаемся
            instance()->queueWithPriority.erase(queueIterator);
        }
                
                //в итоге возвращаем мусор
        return instance()->requestExtract;
    }


как правильно это обработать, по следующей логике... сервер изымает(считывает и удаляет) из очереди нужный запрос и принтит его

может разделить эту функцию на две

первая будет возвращать запрос для принта, а вторая после того как запрос обработается удалять?
PM MAIL   Вверх
asmdzen
Дата 13.8.2011, 08:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



**


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

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



Цитата(JanryMayers @  13.8.2011,  02:03 Найти цитируемый пост)
instance()->requestExtract = new TypeData();


Цитата(JanryMayers @  13.8.2011,  02:03 Найти цитируемый пост)
instance()->requestExtract = &queueIterator->second.back();

может так?
Код

*instance()->requestExtract = *queueIterator->second.back();

тогда этого не должно быть
Цитата(JanryMayers @  13.8.2011,  02:03 Найти цитируемый пост)
//в итоге возвращаем мусор


и не лучше ли чтоб этот requestExtract передавался как параметр функции? после использования кто будет удалять то на что он указывает?

Цитата(JanryMayers @  13.8.2011,  02:03 Найти цитируемый пост)
первая будет возвращать запрос для принта, а вторая после того как запрос обработается удалять? 

будете искать дважды )
PM MAIL   Вверх
JanryMayers
Дата 14.8.2011, 21:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 71
Регистрация: 11.6.2009
Где: Украина, г. Киев

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



Вообщем осталась одна проблема. 

Код

    boost::ptr_vector<Client> clients;
    for(size_t i = 0; i<clientCount; i++){
        DWORD clientID = static_cast<DWORD>(i);
        clients.push_back(new Client(clientID));
    }

    Server* server = new Server();

    while(!_kbhit()){}// остановка процесса

    boost::ptr_vector<Client>::iterator    client;
    for (client = clients.begin(); client != clients.end(); ++client)
    {
        client->stop();
    }

    server->stop();


если клиентов больше 4х

то после срабатывания  остановки процесса... 

программа какбэ зависает, то есть не может завершиться, тк что то ей не даёт этого сделать. 
У кого нибудь есть предположения от чего это и как починить?

Это сообщение отредактировал(а) JanryMayers - 14.8.2011, 21:43
PM MAIL   Вверх
azesmcar
Дата 16.8.2011, 09:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


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

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



Цитата(JanryMayers @  14.8.2011,  21:37 Найти цитируемый пост)
если клиентов больше 4х

то после срабатывания  остановки процесса... 

программа какбэ зависает, то есть не может завершиться, тк что то ей не даёт этого сделать. 
У кого нибудь есть предположения от чего это и как починить?

этот код практически ни о чем не говорит.
что делает client->stop(), server->stop()?

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

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

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

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

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


 




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


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

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