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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Потоки WinApi и GCC, Обуздание потоков 
:(
    Опции темы
NYX
Дата 13.7.2012, 21:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Всем привет! Код
Код

// Внешние включения
#include <cstdio>
#include <string>
using std::string;
#include <windows.h>

// Библиотечные включения
// ...

/********************************************************************/
// Эксперементальный код

class Threaded {
public:

    Threaded(string String) {
        _T_Argument = String;
        _TreadCompleted = false;
        DWORD ThreadID = 0;
        HANDLE ThreadHandle = CreateThread(NULL, 0, _Thread, this, 0, &ThreadID);
    }
    
    ~Threaded() {
        // Здесь можно поставить коунтер, одна итерация которого будет равна 1 микросекунде. И если
        // каунтер > X принудительно завершать поток. Так же вдовесок использовать флаг, который
        // предварительно оценке каунтера попробует завершить поток изнутри (с учетом непопадания
        // в такт, поток может не завершиться и продолжать чота делать. В таком случае, оценка каунтера
        // может 100% гарантировать нормальность в условии что приложение уже счас вот закроется, и
        // ждет только вот этот или несколько подобных потоков с фразой: "ну давай уже хоть как то отрубайся"
        while(!_TreadCompleted)
            Sleep(1);
        Sleep(100);
    }
    
private:

    bool _TreadCompleted;
    
    string _T_Argument;
    
    static DWORD WINAPI _Thread(LPVOID Argument) {
        Threaded *Parent = reinterpret_cast<Threaded*>(Argument);
        for (unsigned int Index = 0; Index < Parent->_T_Argument.length(); Index++)
            printf("%c", Parent->_T_Argument[Index]);
        printf("\n");
        Parent->_TreadCompleted = true;
        return 0;
    }
};

/********************************************************************/
int main(int argc, char** argv) {
    Threaded Thread1("Thread 1");
    printf("Thread 1 completed\n");
    Threaded Thread2("Thread 2");
    printf("Thread 2 completed\n");
    Threaded Thread3("Thread 3");
    printf("Thread 3 completed\n");
    Threaded Thread4("Thread 4");
    printf("Thread 4 completed\n");
    Threaded Thread5("Thread 5");
    printf("Thread 5 completed\n");
    Threaded Thread6("Thread 6");
    printf("Thread 6 completed\n");
    
    return 0;
}


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

* Можно ли утверждать, что отмена Sleep в деструкторе класса Threaded не повлечет за собой трудностей? Конкретизирую - после завершения потока, ОС уничтожает все-про-все и может ли в этот "переходный" момент как то пострадать основной поток при условии что он уже завершается или завершился?

* Как я понимаю, статическая функция-член класса является ОБРАЗЦОМ потока, который создает ОС при вызове CreateThread? То есть можно утверждать, что N классов = N потоков?

* как себя поведет класс если создать его экземпляр через new? Много там кошмаров будет?

Небольшое пояснение - зачем мне это? На данный момент есть такая задача: "написать файлер на подобии стека заданий". То есть, некий класс,
который предварительно принимает задания на действия и после вызова Start задания в стеке класса выполняются. Например вот так:
1) QueryRead(&UnsignedInt, sizeof(unsigned int));
2) QueryRead(&AnsiString, &UnsignedInt);
3) QueryStart(&Percent);
где прототип QueryRead позволяет использовать в качестве первого аргумента указатель на данное В которое надо прочитать данное из файла,
в качестве второго аргумента либо размер читаемого данного, либо указатель на значение размера (который может указывать на ранее прочитанное
данное). А так же и QueryRead(???) который может по результату чтения, как то преобразовывать данные и тутже записывать их куда то. И еще-еще
QueryPosition(unsigned long long *Pos, bool Direction)... в общем вот такая увлекательная механика smile Такой класс в данный момент мне жизненно необходим, так как я смогу читать определенные форматы исходя из парсинга ДОКУМЕНТАЦИИ формата. И фактически, разбор например BMP данных можно будет выполнить с помощью какого то простенького описания во внешнем файле smile Для реализации такого класса задумал использовать:

* Стек заданий - размещает через new структурку в которой описывается задание. Стек является порядком заданий.
* Поток, который - "один объект, один поток", являющийся членом-функцией класса.

В итоге должен получится вот такой вот объект, которых можно было бы сделать например штук пять в одной функции и пока выполняются потоки, функция оценивала бы процент выполнения заданий для всех ИЗВЕСТНЫХ пяти потоков + возможно выполняла бы какие то дополнительные расчеты, например обращалась бы к БД блин или чонить типо того.

(?) В будущем, если все это месиво из кода окажется минимально правильным, я смогу сделать что то вроди ПАЗЛА между объектами класса и что то на подобии пула этих объектов потока, что бы как то более-менее контролировать эту массу зомбо-потоков. Реализация на данный момент не интересует, пока что важны исключительно те моменты которые в списке выше smile
Заранево благодарствую всем уделившим время! smile

Это сообщение отредактировал(а) NYX - 13.7.2012, 21:23
--------------------
'long long long' is too long for GC
PM   Вверх
borisbn
Дата 13.7.2012, 22:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(NYX @  13.7.2012,  21:17 Найти цитируемый пост)
Можно ли утверждать, что отмена Sleep в деструкторе класса Threaded не повлечет за собой трудностей?

Sleep там просто не нужен. Есть Же функции WaitFor...

Цитата(NYX @  13.7.2012,  21:17 Найти цитируемый пост)
То есть можно утверждать, что N классов = N потоков?

т.к. в конструкторе вызывается CreateThread - то, в принципе, можно

Цитата(NYX @  13.7.2012,  21:17 Найти цитируемый пост)
есть, некий класс,
который предварительно принимает задания на действия и после вызова Start задания в стеке класса выполняются

изобретаешь велосипед, ИМХО. Я не очень силён в бусте, но там есть такая штука - asio - судя по тому, что я про неё читал, ты пытаешься сделать её жалкое подобие. Надеюсь boostcoder подключится к обсуждению и более внятно и аргументировано расскажет про азио


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


Опытный
**


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

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



asio::io_service это называется из буста. Занятная штука, плюс, оно само может использовать столько потоков, сколько вы ему дадите. Довольно удобно. Когда-то давно сталкивался с ней для своих нужд, но уже все потерялось и примеров не приведу. smile

PM MAIL   Вверх
borisbn
Дата 13.7.2012, 23:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Randajad @  13.7.2012,  23:10 Найти цитируемый пост)
asio::io_service

ага.... я, конечно, его имел в виду, а не весь asio


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


Бывалый
*


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

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



Эт да, велосипед. Но велосипед изобрести хочется smile так, чисто для себя. Всегда побаивался потоков, а счас решил напрямую в лоб с ними бороться. С бустом не знаком, но наслышан про де-факто стандартной библиотеки. А буст на открытом исходнике? И ваще про НИЗЫ потоков в винде где то есть инфомрация? принципиальная схема так-сказать, где не код простого примера с поверхностным описание под кофе, а как бы рассусоливание с максимальным углублением....? Может книга какая есть? У меня под рукой есть Щупак, в бумажном варианте, там как бы мало углублений.

Это сообщение отредактировал(а) NYX - 14.7.2012, 00:51
--------------------
'long long long' is too long for GC
PM   Вверх
boostcoder
Дата 14.7.2012, 00:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

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



Цитата(NYX @  13.7.2012,  23:45 Найти цитируемый пост)
буст на открытом исходнике?

разумеется =)

Цитата(NYX @  13.7.2012,  23:45 Найти цитируемый пост)
велосипед изобрести хочется

"ох и не легкая это работа, из болота тащить бегемота" (с)

PM WWW   Вверх
NYX
Дата 14.7.2012, 00:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



C WaitForSingleObject должно быть так?

Код

    ~Threaded() {
        unsigned int i; // Чисто для бестолковой итерации
        while(WaitForSingleObject(ThreadHandle, 1)) // проверяем объект ThreadHandle в течении 1 милисекунды
                                                                                // если не АЛЁ, получаем 00000102L оно же WAIT_TIMEOUT ???
            i--; // бестолковая итерация
    }


или тот же ВаитФор в if с ожиданием напр. 1 секунды и если что либо кроме нуля, то уже валить поток принудительно перед завершением главного процесса? Опять таки, не планируется прежде временное завершение... оно нужно скорее на случай подвишивания главного потока во время выхода из программы. иного случая просто не планируется.
--------------------
'long long long' is too long for GC
PM   Вверх
boostcoder
Дата 14.7.2012, 01:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


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

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



Цитата(NYX @  14.7.2012,  00:51 Найти цитируемый пост)
должно быть так?

зачем гадаешь? в описании же все сказано.

PM WWW   Вверх
Dem_max
Дата 14.7.2012, 07:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



я бы добавил следующие функции
bool StartThread(сюда передаем указатель на функцию которую нужно выполнять в потоке); запускает поток.
ExitThread(void); // послать сигнал пользовательской функции на завершение потока.
bool Terminate(void); // завершить поток принудительно.
bool WaitForExitThread(int WaitTime); // функция ожидания завершения потока, вызывается после ExitThread();
int GetExitCode(void); // Возвращает код завершения функции потока.
bool IsStarted(void); // проверяет запущен ли поток


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
NYX
Дата 15.7.2012, 01:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



А значение для GetExitcodeThread где хранится? Есть какой либо риск потерять возвращаемое данное? Напр. в случае разрушения потока каким либо нежелательным образом? Ну, что нибудь рядовое... бывает? Пока что проблем вроди бы не наблюдается у меня, вызываю взятие результа сразу после того как ВэитФор укажет что поток иссяк smile Это как в деструкторе класса так и в функции Stop (остановка потока принудительным образом через терминэйтТреад с кодом эксита = 0)

Это сообщение отредактировал(а) NYX - 15.7.2012, 01:37
--------------------
'long long long' is too long for GC
PM   Вверх
Dem_max
Дата 15.7.2012, 04:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Кстати забыл сказать, крайне не рекомендую создавать поток в конструкторе класса, а то ты можешь в одном классе объявить несколько объектов Threaded, то при создании класса у тебя создадутся несколько нитей(потоков) и будут сразу выполнять действия, хотя эти действия должны допустим выполняться по нажатию кнопки пользователем.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
NYX
Дата 15.7.2012, 14:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



А если создавать в конструкторе в замороженном состоянии и размораживать поток по вызову Start например? В таком случае, выполнение потока будет более резвым, нежели "пока создастся, пока туда-сюда...". А как бы подготовить поток к запуску... и сам запуск делать только по принуждению? Я принципе на данный момент я так и реализовал. Кстати, столкнулся с некой траблой...  не буду погружать в глубины, возник только один вопрос. Деструктор, он же может в своем теле использовать данные-методы-функции своего класса? Просто у меня такая фишка... в деструкторе оттягивается уничтожение объекта само собой до момента пока поток рабочий (жив или заморожен).... но в конструкторе поток заморожен, и если не вызвать Start, прога само собой виснет в ожидании завершения потока. Я в деструкторе повесил Start если поток не запущен (проверяется флаг, состояние которого выставляется в самом потоке) и если флаг false, то он ставится в true вызывается Start и сам поток в момент УСТАНОВКИ флага так же проверяет его состояние и если он ранее установлен в true то поток сразу же завершается. Если false, то ставит true и продолжает выполнение с подвызовом. Это предотвращает выполнение подвызова потока - та самая юзерская функция которая вызывается объектом-потока. В общем механизм вроди бы рабочий, однако Start не срабатывает O_O я вот думаю, может в деструкторе дело? ОллиДбг показывает что поток в момент деструктора еще заморожен и есть.. .не убит. Но пощему то чот не срабатывает.

Это сообщение отредактировал(а) NYX - 15.7.2012, 15:31
--------------------
'long long long' is too long for GC
PM   Вверх
Dem_max
Дата 15.7.2012, 16:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата

А если создавать в конструкторе в замороженном состоянии и размораживать поток по вызову Start например? В таком случае, выполнение потока будет более резвым, нежели "пока создастся, пока туда-сюда...". 

собственно так и сделано у Borland

Цитата

В основной программе создайте объект этого потокового класса
 // создаем поток в приостановленном состоянии (true), запущенном (false)

TMyThread *Thr = new TMyThread(true); // в приостановленном 

Если вы заметили, в конструкторе есть параметр bool CreateSuspended, если при создании
 объекта этот параметр имеет значение false, поток сразу - при создании объекта начнет свою работу,
 то есть начнется выполнение кода в методе Execute(), если параметр bool CreateSuspended true, будет создан
 поток в приостановленном состоянии, для запуска потока вам требуется применить методом Resume()
Thr->Resume();


Цитата

Деструктор, он же может в своем теле использовать данные-методы-функции своего класса?

все может использовано что объявлено в классе


Цитата

ОллиДбг показывает что поток в момент деструктора еще заморожен и есть.. .не убит. Но пощему то чот не срабатывает.


Для деструктора:
Проверяй валиден ли хэндл потока, если да посылай сигнал завершения потока, дожидайся заврешение потока по конкретному таймауту, если таймаут истек делай Terminate потока.

Это сообщение отредактировал(а) Dem_max - 15.7.2012, 16:21


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
NYX
Дата 15.7.2012, 18:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Де жути пугают использования TerminateThread, боюсь как бы потом не было таких ошибок... которые непойми откудасыпятся. Начитался ужасов про все виды завершения кроме естественного выхода из потока по завершению. А еще вопрос, вот полчуается как.... если распаралелить и пустить все потоки в разнобой, они ведь будут быстрее выполняться чем если их сонхронизировать? И прирост производительности, навскидку будет невысоким если синхронизировать ВСЕ потоки включая главный?
--------------------
'long long long' is too long for GC
PM   Вверх
Randajad
Дата 15.7.2012, 18:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Зависит от частоты синхронизаций. Если они у вас все делать синхронно будут - прироста нет.
Не вижу проблемы для создания потоков. На их создание уходит не такое уж и большое время.

Если использовать std:: или boost::thread, то никаких termitate не нужно.

Это сообщение отредактировал(а) Randajad - 15.7.2012, 18:27
PM MAIL   Вверх
Dem_max
Дата 15.7.2012, 18:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата

то никаких termitate не нужно

Да ну ???? и что же случается с зависшим потоком ???? он так и остается висеть в памяти ???


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Randajad
Дата 15.7.2012, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Почему он зависнет? Есть thread::join, которое и нужно юзать.
PM MAIL   Вверх
Dem_max
Дата 15.7.2012, 18:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Ну потому что например в потоке бесконечный цикл запущен. 


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Randajad
Дата 15.7.2012, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Ну запущен - пусть делает себе бесконечный цикл, раз надо. Что такого?
PM MAIL   Вверх
Dem_max
Дата 15.7.2012, 18:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Ну поток должен быть завершен, если это требуется.
Вопрос как его завершить ???


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
borisbn
Дата 15.7.2012, 20:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Dem_max @  15.7.2012,  04:58 Найти цитируемый пост)
Кстати забыл сказать, крайне не рекомендую создавать поток в конструкторе класса

вот был (и остаюсь) точно такого же мнения.... но, когда увидел boost::/std:: thread - был немного удивлён. Там как раз наоборот - запускают поток в конструкторе (и мало того - в деструкторе - не ожидают завершения работы потока)... странно...


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


Бывалый
*


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

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



В будущем конечно я уже буду использовать готовые реализации объектов-потоков. Но пока что надо разобраться в тонкостях этих потоков. В любооом случае, это надо знать smile
...
Все, разобрался с деструктором. Все арбайтен! Там с помощью флагов теперь поток размораживется и если подвызов потока не произошел, то поток завершается без подвызова. Если поток по каким либо причинам завис, то деструктор не даст удалить объет до того момента пока поток не развиснет. Так что поток вечен в этом плане. Если надо предотвратить работу потока (возможно принудительно) то через Stop в аргументе которого указывает интервал ожидания smile Осталось терь разобарться с синхронизацией и придумать коллектор объектов-потоков ответсвенный за всех сынов своих. А может даже и возможность пазла в коллекторе под еще один, для контроля целой матрицы потоков. Кстати на случай необходимости, можно ведь повесить флаг в конструкторе, мол "Запустить его сразу? Или ждать вызова Start?"

Это сообщение отредактировал(а) NYX - 15.7.2012, 20:44
--------------------
'long long long' is too long for GC
PM   Вверх
NYX
Дата 15.7.2012, 20:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Прототип
Код

namespace Z {
    namespace Basis {
        class Thread;

        typedef unsigned long (*thread_action)(void *Argument, Thread *Parent); // ...........................................................> Функция вызываемая потоком

        struct thread_argument {
            thread_action Action; // .........................................................................................................> Указатель функции для вызова потоком
            void *Argument; // ...............................................................................................................> Аргумент для функции вызываемой потоком
        };

        class Thread {
        public:

            Thread(thread_action Action, void *Argument, unsigned long *Return); // ..........................................................> Конструктор
            /* Конструктор объекта потока принимающий в качестве аргументов указатель на функцию подвызова потока, указатель на аргументы
             * передаваемые потоку (пользовательской функции - подвызову потока). Параметр Return является указателем на вшенюю переменную
             * для возвращаемого значения потока. В качестве данного аргумента можно указать NULL. В любом из случаев, объект потока вернет
             * код выхода потока при вызове GetExitCode если поток завершен. */

            ~Thread(); // ....................................................................................................................> Деструктор
            /* Деструктор не завершает поток принудительно, он ожидает завершение потока. Если поток не была запущен, то деструктор завершает
             * поток без его выполнения подвызова (рекомендуемым способом, без применения TerminateThread) */

            unsigned int Start(); // .........................................................................................................> Запустить поток
            /* Метод размораживает поток в случае вызова после конструктора. Если вызов повторный, проверяется активность потока. Если поток
             * завершен, производится сброс объекта и повторный вызов потока. Если поток еще выполняется, данный вызов игнорируется */

            bool Pause(unsigned int Delay); // ...............................................................................................> Заморозить поток
            /* Функция замораживает поток. В случае если Delay равен нулю, поток замораживается до вызова Start. Если Delay больше нуля, то
             * поток замораживается на периуд указанный в Delay. */

            bool Stop(unsigned int Wait); // .................................................................................................> Остановить поток
            /* Принудительное завершение потока. Параметр Wait Указывает количество десятых секунды ожидания. Если значение Wait равное нулю,
             * то поток завершается вызовом TerminateThread с кодом выхода 0. Если Wait больше нуля, то функция ожидает заданный периуд в
             * десятых долях секунды, и если поток не завершился, вызывается TerminateThread с кодом выхода равным 0 */

            bool Wait(); // ..................................................................................................................> Ожидание завершения потока
            /* Проверяет активность объекта. (!) Может привести к зависанию главного потока в случае если не был произведен вызов Start */

            unsigned long GetID(); // ........................................................................................................> Взять идентификатор потока
            /* Возвращает идентификатор потока */

            void *GetHandle(); // ............................................................................................................> Взять дескриптор потока
            /* Возвращает дескриптор (адрес объекта ядра) потока */

            unsigned long GetExitCode(); // ..................................................................................................> Взять код возврата потока
            /* Возвращает код выхода потока. Если поток не завершен, возвращается значение 0. Для проверки завершенности потока можно
             * использоваться функцию Wait, но при условии предварительного вызова Start */

        private:
            thread_argument _ThreadArgument; // ..............................................................................................> Структура аргументов для потока
            unsigned long *_Return; // .......................................................................................................> Указатель на значение возвращаемое потоком
            unsigned long _ThreadExitCode; // ................................................................................................> Код возврата потока

            bool _ThreadStartControl; // .....................................................................................................> Флаг контроля запуска потока
            bool _ThreadCompleted; // ........................................................................................................> Флаг завершенности потока

            unsigned long _ThreadID; // ......................................................................................................> Идентификатор потока
            void *_ThreadHandle; // ..........................................................................................................> Дескриптор потока

            static unsigned long __stdcall _ThreadFunction(void *Argument); // ...............................................................> Функция потока
        };
    }
}


Реализация
    Функция _Format это аналог sprintf тока возвращающий string, вместо аргумента указателя результирующей строки str 
    Функция IternalShellError это функция которая выводит ошибку либо в консоль, либо в MessageBox и завершает приложение ExitProccess
    Оповещение об ошибке на скорую руку smile
Код

Z::Basis::Thread::Thread(thread_action Action, void *Argument, unsigned long *Return) {
    _ThreadArgument.Action = Action; // ......................................................................................................> Присвоения указателя пользовательской функции
    _ThreadArgument.Argument = Argument; // ..................................................................................................> Присвоение указателя на аргументы
    if (Return == NULL) { // .................................................................................................................> Проверка указателя на внешнюю переменную кода выхода ->
        _Return = &_ThreadExitCode; // .......................................................................................................> Берется указатель переменной объекта
        _ThreadExitCode = 0; // ..............................................................................................................> Оонуление переменной кода возврата объекта
    } else {
        _Return = Return; // .................................................................................................................> Присваивается указатель на внешнюю переменную
        *_Return = 0; // .....................................................................................................................> Обнуление внешней переменной кода возврата
    }

    _ThreadStartControl = false; // ..........................................................................................................> Флаг контроля запуска потока
    _ThreadCompleted = false; // .............................................................................................................> Флаг завершенности потока

    _ThreadID = 0; // ........................................................................................................................> Обнуление идентификатора потока
    _ThreadHandle = CreateThread(NULL, 0, &_ThreadFunction, this, CREATE_SUSPENDED, &_ThreadID); // ..........................................> Создание потока
    if (_ThreadHandle == NULL) { // ..........................................................................................................> Дескриптор потока пуст - поток не создан
        Z::InternalShellError("Failed to create thread");
    }
}

Z::Basis::Thread::~Thread() {
    if (!_ThreadStartControl) { // ...........................................................................................................> Проверка флага контроля запуска потока ->
        _ThreadStartControl = true; // .......................................................................................................> Поток неактивен - необходим запуск с завершением
        Start(); // ..........................................................................................................................> Запуск а завершением
    }

    bool ThreadWork = true; // ...............................................................................................................> Флаг активности потока
    while (ThreadWork) { // ..................................................................................................................> Цикл проверки активности потока ->
        unsigned long WaitResult = WaitForSingleObject(_ThreadHandle, 100); // ...............................................................> Проверка занятости объекта
        if (WaitResult == WAIT_OBJECT_0) // ..................................................................................................> Поток завершился ->
            ThreadWork = false; // ...........................................................................................................> Выход из цикла проверки активности
        else if (WaitResult == WAIT_FAILED) // ...............................................................................................> Ошибка проверки активности потока
            Z::InternalShellError(_Format("Failed to wait thread %lu", GetLastError()).c_str()); // ..........................................> Оповещение об ошибке
    }
    
    if (CloseHandle(_ThreadHandle) == 0) // ..................................................................................................> Попытка закрыть дескриптор потока
        Z::InternalShellError(_Format("Failed to close thread handle %lu", GetLastError()).c_str());
    
    GetExitCode(); // ........................................................................................................................> Взятие кода возврата потока
}

unsigned int Z::Basis::Thread::Start() {
    if (_ThreadCompleted) { // ...............................................................................................................> Проверка завершенности потока ->
        _ThreadStartControl = false; // ......................................................................................................> Сброс флага контроля запуска потока
        _ThreadCompleted = false; // .........................................................................................................> Сброс флага завершенности потока
        _ThreadID = 0; // ....................................................................................................................> Обнуление идентификатора потока
        _ThreadHandle = CreateThread(NULL, 0, &_ThreadFunction, this, 0, &_ThreadID); // .....................................................> Создание и запуск потока
        return 2; // .........................................................................................................................> Новый поток создан и запущен на выполнение
    }

    unsigned long WaitResult = WaitForSingleObject(_ThreadHandle, 0); // .....................................................................> Проверка занятости объекта
    if (WaitResult == WAIT_OBJECT_0) // ......................................................................................................> Поток завершился ->
        return 0;
    else if (WaitResult == WAIT_FAILED) // ...................................................................................................> Ошибка проверки активности потока
        Z::InternalShellError(_Format("Failed to wait thread on start %lu", GetLastError()).c_str()); // .....................................> Оповещение об ошибке

    if (ResumeThread(_ThreadHandle) == -1) // ................................................................................................> Попытка разморозки потока
        Z::InternalShellError(_Format("Failed to resume thread %lu", GetLastError()).c_str()); // ............................................> Оповещение об ошибке
    return 1;
}

bool Z::Basis::Thread::Pause(unsigned int Delay) {
    unsigned long WaitResult = WaitForSingleObject(_ThreadHandle, 0); // .....................................................................> Проверка занятости объекта
    if (WaitResult == WAIT_OBJECT_0) // ......................................................................................................> Поток завершился ->
        return false;
    else if (WaitResult == WAIT_FAILED) // ...................................................................................................> Ошибка проверки активности потока
        Z::InternalShellError(_Format("Failed to wait thread on pause %lu", GetLastError()).c_str()); // ......................................> Оповещение об ошибке

    if (SuspendThread(_ThreadHandle) == -1) // ...............................................................................................> Попытка заморозки потока
        Z::InternalShellError(_Format("Failed to suspend thread %lu", GetLastError()).c_str()); // ...........................................> Оповещение об ошибке
    
    if (Delay > 0) { // ......................................................................................................................> Если время заморозки больше нуля ->
        Sleep(Delay); // .....................................................................................................................> Задержка перед разморозкой
        Start(); // ..........................................................................................................................> Разморозка потока
    }
    
    return true;
}

bool Z::Basis::Thread::Stop(unsigned int Wait) {
    for (unsigned int Index = 0; Index < Wait; Index++) { // .................................................................................> Цикл ожидания потока ->
        if (WaitForSingleObject(_ThreadHandle, 100) == 0) { // ...............................................................................> Итерация цикла ожидания ->
            GetExitCodeThread(_ThreadHandle, _Return); // ....................................................................................> Взятие кода возврата потока
            return true;
        }
    }
    
    TerminateThread(_ThreadHandle, 0); // ....................................................................................................> Принудительное завершение потока
    GetExitCode(); // ........................................................................................................................> Взятие кода возврата потока
    return false;
}

bool Z::Basis::Thread::Wait() {
    unsigned long WaitResult = WaitForSingleObject(_ThreadHandle, INFINITE); // ..............................................................> Ожидание завершения потока
    if (WaitResult == WAIT_OBJECT_0) // ......................................................................................................> Потока завершился
        return true;
    else if (WaitResult == WAIT_FAILED)
        Z::InternalShellError(_Format("Failed to wait thread %lu", GetLastError()).c_str()); // ..............................................> Оповещение об ошибке
}

unsigned long Z::Basis::Thread::GetID() {
    return _ThreadID;
}

void *Z::Basis::Thread::GetHandle() {
    return _ThreadHandle;
}

unsigned long Z::Basis::Thread::GetExitCode() {
    GetExitCodeThread(_ThreadHandle, _Return); // ............................................................................................> Взятие кода возврата потока
    return *_Return;
}

unsigned long __stdcall Z::Basis::Thread::_ThreadFunction(void* Argument) {
    Thread *Parent = reinterpret_cast<Thread*> (Argument); // ................................................................................> Приведение типа указателя

    if (Parent->_ThreadStartControl) // ......................................................................................................> Проверка флага контроля запуска потока ->
        return 0; // .........................................................................................................................> Запуск отменяется - завершение потока
    else // ..................................................................................................................................> Запуск разрешен ->
        Parent->_ThreadStartControl = true; // ...............................................................................................> Отметка о произведенном запуске потока

    unsigned long Return = Parent->_ThreadArgument.Action(Parent->_ThreadArgument.Argument, Parent); // ......................................> Вызов пользовательской функции потока
    return Return; // ........................................................................................................................> Возврат значения пользовательской функции потока
}


Добавлено @ 20:58
Там в Pause используется Sleep. Дело неблагодарное, так как заснет все, не только замораживаемый поток smile Это не к чему. Может имеет смысл для онной реализации использовать поток коллектора (единственный на объект коллектора...) или ваще отнять эту возможность. В общем, это я так, для ассортимента вставил, Sleep этот.

main
Код

unsigned long ThreadFunction(void *Argument, Z::Basis::Thread *Parent) {
    string *ArgumentString = reinterpret_cast<string*>(Argument);
    printf("Im a ID:%lu HANDLE:%p thread with a `%s` argument and im guess return 666 value. It's there? \n", Parent->GetID(), Parent->GetHandle(), ArgumentString->c_str());
    return 666;
}

int main(int argc, char** argv) {
    system("cls");
    unsigned long Ret = 0;
    string StringForThread("ArgString");
    Z::Basis::Thread _Thread_A(&ThreadFunction, &StringForThread, NULL);
    Z::Basis::Thread _Thread_B(&ThreadFunction, &StringForThread, NULL);
    
    _Thread_A.Start();
    _Thread_A.Wait();
    
    printf("Ret is %lu\n", _Thread_A.GetExitCode());
    if (_Thread_A.GetExitCode() == 666)
        printf("That's OK!");
    
    return 0;
}


Это сообщение отредактировал(а) NYX - 16.7.2012, 01:49
--------------------
'long long long' is too long for GC
PM   Вверх
Randajad
Дата 15.7.2012, 23:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



atomic_bool и в бесконечном цикле в потоке ее проверять. Разве не  так? Или вы хотите с помощью Termonate его жестоко убить? smile
PM MAIL   Вверх
NYX
Дата 16.7.2012, 00:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



атомарный флаг.... эммм... а куда его пихать то? В перерывах выполнения пользовательской функции-потока? Не, я понял.... но почему атомарный? Кто еще будет читать\писать флаг?  smile  о боги я еще не в курсе синхронизации... был перерыв на сон. Счас активизировался для пожирания информации.

Это сообщение отредактировал(а) NYX - 16.7.2012, 00:12
--------------------
'long long long' is too long for GC
PM   Вверх
Alca
Дата 16.7.2012, 00:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата

Всегда побаивался потоков, а счас решил напрямую в лоб с ними бороться


https://bitbucket.org/skynowa/xlib/src/7091...Sync/CxThread.h
https://bitbucket.org/skynowa/xlib/src/7091...nc/CxThread.cpp

Это сообщение отредактировал(а) Alca - 16.7.2012, 00:17


--------------------
PM WWW ICQ Skype Jabber   Вверх
Randajad
Дата 16.7.2012, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Это был на вопрос участника выше: что делать в бесконечном цикле. smile
Проверять эту атомарную переменную и завершать выполнение цикла, если она, например, == true. Зачем атомарную? Компилятор может ее выкинуть из цикла, ибо посчитает, что она не изменяется. Хотя. Можно сделать не атомарную, а volatile.
PM MAIL   Вверх
NYX
Дата 16.7.2012, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



На GCC нет _beginthread :(
Но для общего принципа исходники интересны. Гранд рахмад за писчу для ума! Да и ваще всем спасибо за помосч smile Буду ковыряться, постепенно писать о результах прогресса.
КСТАТИ! Об указании на НЕОБХОДИМОСТЬ ПРИСУТСТВИЯ! Надо и это мне тоже учесть... таааак.

http://alenacpp.blogspot.com/2006/04/volatile.html

Это сообщение отредактировал(а) NYX - 16.7.2012, 01:05
--------------------
'long long long' is too long for GC
PM   Вверх
Dem_max
Дата 16.7.2012, 05:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата

Это был на вопрос участника выше: что делать в бесконечном цикле. 
Проверять эту атомарную переменную и завершать выполнение цикла


Бесконечный цикл это к примеру. Ну в коде с большой вероятностью может присутствовать такая строчка
WaitForSingleObject(hHandle, INFINITE);

Ну и если событие по каким то причинам никогда не наступит, то все поток весит. Никакие флаги не спасут отца русской демократии.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Randajad
Дата 16.7.2012, 10:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Говнокодить не надо, чтобы оно по каким-то причинам не наступило. smile

Добавлено через 25 секунд
Это к сабжу уже не относится, кстати. smile
PM MAIL   Вверх
Dem_max
Дата 16.7.2012, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Ну в сабже есть такой как раз момент.
Если эта функция будет в потоке, который породил еще один поток.
Код

bool Z::Basis::Thread::Wait() {
    unsigned long WaitResult = WaitForSingleObject(_ThreadHandle, INFINITE); // ..............................................................> Ожидание завершения потока
    if (WaitResult == WAIT_OBJECT_0) // .



--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
NYX
Дата 16.7.2012, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



В реальности врядли будет вообще использоваться эта функция smile Я написал ее просто что бы main преждевременно не вылетала smile Да и с небольшим мэйном если приложение виснет, в Olly просто условие немного меняю и прога развисает smile В Wait можно аргументы поставить что бы не было вечного ожидания. А ваще принципиально от INFINITE ничем не застр###шься. Так что, не знаю, как-то не хочется выдумывать всякого рода хаки. Я думаю что чем примитивныее объект-поток, тем более он будет гибок. Вот только с синхронизацией подразбирусь и с атомарностью. Кстати, а кто нибудь может рассказать про критические секции? А то у щупака просто выложено как ФАКТ что такое есть + описание объектов. Но в связке с потоками примера не описано. Мьютексы и семафоры это ясно, они в теле потока уже там туда-сюда-используются... а вот с критическими секциями ничо не понял. А, ну на WinAPI если кто то использовал. Хотя если принцип такой есть в какой то библиотеке, то можно и на примере библиотеки.

Это сообщение отредактировал(а) NYX - 16.7.2012, 13:24
--------------------
'long long long' is too long for GC
PM   Вверх
NYX
Дата 16.7.2012, 18:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Расковырял инфы про критические секции. Собстно вот статья http://www.rsdn.ru/article/baseserv/critsec.xml
Стало быть:
* Критическая секция это объект, размещение которого определяется функциями EnterCriticalSection и LeaveCriticalSection в параметрах которых
принимается указатель на объект секции. Далее, перед оперированием какого либо данного, делается ентер, по завершению оперирования
лив. Соответственно можно использовать вложенные ентеры и ливы, если например поток может обращаться ЛИБО - ЛИБО соответственно.
так же выходит, область критической секции не начнет свое выполнение и не прервется по середине. Весч прикольная. Но почему тогда
такие лакомые плюшки мало где используются? Напр. сервера, где почти во всех как в одном юзаются мьютексы или симафоры. В сильно взрослых
серверах типо апача (мельком просмотрел) тоже вроди бы мьютексы, в микросервере null httpd...
А что стоило бы, например, внутренние данные объекта потока защитить критсекциями... плюс, дать возможность объекту-потоку принимать
объект критсекции, или более того... если имеется подвызов, то просто обуславливать его вызовами ентер и лив. Тогда ВСЕ используемое в потоках-
потомках коллектора будет (типо)атомарным. А в случае если например используется связка коллекторов... то можно использовать нечто вроди
массива (стека?) объектов критических секций. Довести до автоматизма опрос списка секций в выполнении определенных задач (ну типо не все
элементы объекта, а зависимые от выполнимой задачи). Ух! Сколько всего придется погрызть и попробовать на зуб.
--------------------
'long long long' is too long for GC
PM   Вверх
Dem_max
Дата 16.7.2012, 18:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата

(типо)атомарным

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

Цитата

Но почему тогда
такие лакомые плюшки мало где используются?

Используются

Цитата

В операционных системах семейства Microsoft Windows разница между мьютексом и критической секцией в том, что мьютекс является объектом ядра и может быть использован несколькими процессами одновременно, критическая секция же принадлежит процессу и служит для синхронизации только его потоков.

Критические секции Windows имеют оптимизацию, заключающуюся в использовании атомарно изменяемой переменной наряду с объектом «событие синхронизации» ядра. Захват критической секции означает атомарное увеличение переменной на 1. Переход к ожиданию на событии ядра осуществляется только в случае, если значение переменной до захвата было уже больше 1, то есть происходит реальное «соревнование» двух или более потоков за ресурс.

Таким образом, при отсутствии соревнования захват/освобождение критической секции обходятся без обращений к ядру.



--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
NYX
Дата 16.7.2012, 19:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Ну да но я и написал ТИПО smile само собой никакой атомарности нет smile А где например используются? Глянуть бы исходники... На сайте IBM (не вспомню уже где я это и как нашел) статья была про легкие сервера (ПО разумеется)... там были ссылки я частично поразглядывал исходники, но там по большей части на разных языках где ... нет того что в С++ пожжерживается. Единственное более менее подходящее null httpd было и счас на харде лежит, он под МС но принцип примерно такой же как и при WinAPI CreateThread (почти). В общем смысил один за исключением _beginthread. но там нет крит. секций. Апач даже ковырять толком не стал smile жутко стало при одном виде smile недели две-три придется на листке всю модель выписывать + еще хз сколько времени на то что бы отсечь лишнее и внять логику. Да и к тому же там тоже вроди бы нет критических секций. Ну хотя с секциями я относительно более менее разобрался для себя, хотя пример лучше бы узреть. Пойду гуглить smile
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 17.7.2012, 12:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Цитата(Dem_max @  16.7.2012,  19:24 Найти цитируемый пост)
Типо атомарным не будет никак, атомарнось подразумевает выполнение чего либо за один такт процессора.
Да ладно?  smile А если процессор в принципе не имеет ни одной инструкции, которая выполнялась бы быстрее n>1 тактов? Более того, современные процессоры (x86) выполняют инструкции не за один такт. Просто, пока одна инструкция выполняется, следующая дешифруется, а третья извлекается из памяти (это упрощенно).
Может все-таки стоит почитать определение атомарности?
PM   Вверх
NYX
Дата 17.7.2012, 15:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Типо конвеерность все такое smile Всеж атомарность получается может поддерживаться железом, но это не зависит от кол-ва действий. Атомарным является данное которое в данный момент времени доступно одному потоку и нерушимо остальными потоками. Тогда получается мое утверждение об атомарности - не типо атомарное, а полноценно атомарное (об критических секциях).

Это сообщение отредактировал(а) NYX - 17.7.2012, 15:32
--------------------
'long long long' is too long for GC
PM   Вверх
NYX
Дата 19.7.2012, 14:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Все! Я Запутался.
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 19.7.2012, 14:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Цитата(NYX @  19.7.2012,  15:07 Найти цитируемый пост)
Все! Я Запутался. 

в чем? в атомарности?
PM   Вверх
NYX
Дата 19.7.2012, 16:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Да в ней акаянной! Вот, критические секциии ваще вынесли мне мозг. Ступор произошел еще в самом начале, когда была попытка как то изолировать данные класса-потока от множественных обращений к ним из:
1) внутренней реализации потока
2) внешних вызовов других потоков в т.ч. главного потока процесса

Путаница началась с вложенностью критических секций, а так же возможность дедлока в случае витиеватых возможностей класса. В какой то момент он может получиться, в какой то - нет. ООООЙ БОЖЕ!!! Это какой то АД! Вот логически потоки понять реально. А вот как сделать наиболее примитивную - простую автомарность. Пусть даже код будет избыточным, но его понимание было бы простым. Я уже подумываю сделать реализацию потоков и атомарности с помощью низкого уровня. Мне кажется что такая реализация даже будет лушче. Например, привязка данного к потоку. В случае если от коллектора ответвлено более одного потока, коллектор не опзволит обратиться к подключенным к нему данным. Это всего то лишь надо сделать подобие встроенных типов данных, а точнее дополнить POD парочкой флагов и полей под идентификатор коллектора. В общем решить на низком уровне будет от части и сложнее и проще... но блин опять же гемор, это все будет делаться ВНЕ реализации какого либо проекта и если надо будет подызменить реализацию, надо будет пересобирать например ту же DLL работающую с потоками и переподключать.... в общем пипец.
Может есть какая то стандартная схема гарантирующая атомарность данных? что бы можно было бы буквально просто указывать, -> вот тебе внешние данные товарищь поток, читай там оверхед (или какой нибудь объект рядом с ними) и смотри, не балуй с чтением\записью.

Да, кстати, в критических секциях я запутался в силу того, что не понял как они работают в низах. Вот допустим, выделил я внутри реализации потока блок кода и работы с данными. Окей. Второй, дублирующий этот код в своем потоке - поток, не может обратиться до тех пор пока ЭТА СЕКЦИЯ кем -то занята. Окей. с этим все ясно. А если допустим, я хочу изолировать вызовы printf для двух потоков в двух областях кода? Это надо писать и там и там EnterCriticalSection. Окей, а если рядом с вызовом printf используется инициализация какого то обхекта, и делается в одном из двух экземпляре. Но опять же может использоваться другими двумя потоками. Надо делать опять очередную критсекцию? Обобщаться все эти блоки, для выявления общих секций, которые не нарушили бы данные... блин это просто АД!  smile 

Это сообщение отредактировал(а) NYX - 19.7.2012, 16:57
--------------------
'long long long' is too long for GC
PM   Вверх
NYX
Дата 19.7.2012, 19:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



 smile  я даже представить не могу как ваще проводить тестирование многопоточных приложений ухахаха
мои мозги в кофемолке  smile 
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 19.7.2012, 23:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Цитата(NYX @  19.7.2012,  20:52 Найти цитируемый пост)
 я даже представить не могу как ваще проводить тестирование многопоточных приложений ухахаха

думаю, это вообще мало кто представляет. smile 
Цитата(NYX @  19.7.2012,  17:53 Найти цитируемый пост)
Да, кстати, в критических секциях я запутался в силу того, что не понял как они работают в низах.

просто Microsoft назвала критической секцией то, что обычно называют захватом мьютекса. Так как они мьютекс сделали ядерным. Так вот, забудь про ядерный мьютекс. Речь идет о межпоточных мьютексах (фьютексах). Реализуются они через простейший атомарные операции процессора. При захвате мьютекса происходит изменение целочисленной переменной. При одном значении мьютекс считается успешно захваченным, при других значениях он считается захваченным другим процессом, в итоге текущий поток передает управление ядру. При возврате управления происходит еще одна попытка захвата... Если интересуют детали, то см. http://locklessinc.com/articles/mutex_cv_futex/
PM   Вверх
NYX
Дата 20.7.2012, 00:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Стало быть сложность критических секций заключается в том, что нет ЯВНОСТИ указания "кто ваще кого чо?". Фьютекс является "Сходным образом оптимизированы объекты CRITICAL_SECTION в Win32 API, а также FAST_MUTEX в ядре Windows" по словам википедии. Сейчас более менее начал вникать в назначение мутексов и семафоров, благодаря какому то документу из НГУ на тему "Аспекты параллелизма", который описывает аспекты и реализации для Win\Linux после основополагающей теории. Буквально спас меня этот документ. Он был послан богами свыше, однозначно  smile ! Значит, получается что... критические секции, это своего рода IF с возможностью try на случай если помимо блока IF имеются какие либо еще задачи. В случае с мьютексами и симафорами это уже принудительное самоисключение потока из очереди (вне реализации, скажем так по теории). Получается что... для точного определения, что надо использовать, мьютексы, семафоры или некий гибрид "критическую секцию", необходимо точно знать какая задача у этих потоков и уже применять ТОТ или ИНОЙ способ, возможно зонально, а возможно на уровне ассортимента или наследственности объектов (для С++). 

Я решил поставить для себя такую задачу, которая не относится к реальным требованиям или реальным мирским потребностям. Выучить потоки на примере сервера, где модель сервера примерно такая:
1) поток который обрабатывает входящие данные и формироует очередь сообщений (подразумевается логика писатель-читатель)
2) множество потоков которым отведена ЧАСТЬ очереди (группировка и разнообразие потоков может диктоваться например скоростью соединения)
3) поток который производит рассылку обработанных данных по клиентам.

Как можно реализовать такую модель? Какие средства обеспечения атомарности данных необходимы для реализации. Попробую налету сформировать
подзадачи.
1) Поток принимающий данные от пользователя, позволяет засыпать\просыпаться потоку 2го пункта. Это важно! На случай если клиентов очень много но все они в разных категориях. Так, получится что для медленных клиентов с нечастыми запросами поток будет засыпать чуть чаще, но приоритет таких потоков (на уровне выполнения ОС) будет немного выше других.
2) потоки обрабатывающие данные, должны учитывать определенные условия. Например, поступившие данные от U1 на загрузку файла. Но, в процессе загрузки файла, U2 изменил пару байт. Варианта два - 1) прекратить закачку, дождаться обновления и самовозобновить закачку ( эгоизм среди потоков! О да, рекомендуемо). 2) Дождаться закачки - обновить данные (не рекомендуемо в силу больших потреблений ресурсов ЦП и трафика, так как более новое данное один шишъ придется закачивать по новой, но юзверь может и не знать о том, что данное было обновлено!!!!! ЭТО ВАЖНО!).
3) Потоки рассылки, являются чем то вроди дублирующего усилителя (аля РЭА). Где например, находящиеся в ОДНОМ ЗАЛЕ ОБМЕНА ФАЙЛАМИ учитываются такие условия описанные в пункте 2. То есть, грубо говоря, сервер и потоки могут быть уверены, что U1 не нарушит данные обрабатываемые в другом ЗАЛЕ для U234-517. Сами по себе потоки, могут пробуждаться в случае если очередь не пустая. Опять же, потоки могут обрабатывать отдельные части очередей. ХОТЯ! Все эти области очередей можно представить в виде множества стеков smile Как для потоков 1го пункта так и для 3го пункта. Очереди в таком смысле будет своего рода связанными... то есть, если есть очереди для 1го потока в виде QS[1...3] то и для 3го пункта потоков так же QS[1...3]. Наиболее важное! U[?] пользователи могут перестраиваться в произвольный момент времени из одной QS в другую!
ДАДАДА! Что я еще заметил! У пользователя можно установить мин-макс ( 0 < ?) пунктов очереди, и уже ранее сконфигурированный сервер при авторизации пользователя, создал бы болванку пустой очереди! Хотя в представлении очереди как СТЕКА это очень сложно... представить... маллок и реаллок и прочее что ли? В общем это второстепенно уже наверно.
Это образно. Но я думаю что выполнив такую задачу, потоки будут для меня семечками. Хочется додуматься самому, но сейчас понимаю, что на это надо время, поэтому взываю о помощи опытных людей smile

Как вы думаете? Вот навскидку, без кода и примеров, сугубо на пальцах, как такое реализовать используя мьютексы-семафоры-критсекции? Что будет избыточным? Что будет необходимым? smile

стало быть имеется получается вот что:
U1 -\_ QS1 ~ TI -> TC -> TO (thread in -> thread calc -> thread out)
U2 -/

U3 - QS2 ~ TI -> TC -> TO

U4 -\
U5 - |_ QS3 ~ TI -> TC -> TO
U6 -/

То есть в своем начале, каждый юзер имеет 3 потока Вход -> обработка -> выход, и в случае (ухахаха ИНТИМНОЙ) близости юзверей, их потоки сливаются в едином экстазе обрабатывая ВСЕ их запросы по некой событийности.

Значит, общими данными могут явиться данные, у которых более 1го владельца. Вроди бы логично получается. Чего стоит указать потоку с каким мьютексом из множества он имеет дело.. допустим так.

Далее, отделиться от очереди и перейти в свою... может означать копирование не обработанных данных СТАРОЙ ОЧЕРЕДИ, ровно таким же образом как и слияние очередей... но можно сделать очередь для множества, как массив очередей, где i оперируемая поток очередь на данный момент времени. Очередь является атомарным данным (ну или для корректности, множеством атомарных данных. Хотя первое наверно точнее, так как элементы в целом и есть неделимое для потоков данное). Окей, с этим более менее разобрались. Но как внутри этой всей схемы, идентифицировать юзверей например по категории скорости соединения? Так как ->
* Пользователи со скоростью соединения ОТ и ДО принадлежат одной группе, а те что от ДО и ДО-ДО ко второй....
* Те кто в группе с низким пропускным каналом обрабатываются приоритетнее чем те у кого канал быстрее. Если в очереди стоят 3-4 потока на группу быстрых клиентов и появляется медленный, то после НЫНЕШНЕГО клиента сразу идет медленный, после чего обслуживаются те 3-4 быстрых, если более нет медленных. ДА! Только так. Сервер можно будет допустим конфигурировать низший порог скорости + кол-во низших скоростных клиентов, дабы не приводить к обработке ТОЛЬКО низших клиентов. Это уже иная задача и в целом это дело можно контролировать например вручную, админам! Иначе, для чего они тогда нужны админы, как если не для этого smile

ДАЛЕЕ!
Уже вроди бы более менее мне ясно что да как.... но вот вопрос smile Что если например будет необходимо разбить 3 типа потоков на 2 процесса, где 1 процесс выполняет функцию некого воркера, работающий только с формированием очереди и с I\O, а второй процесс отвечает за вычисления и отправку запросов на БД например, в которой хранятся файлы. Опять же, мутексы, фьютексы, семафоры, критсекции... кошмар. УЖАС!

Это сообщение отредактировал(а) NYX - 20.7.2012, 01:25
--------------------
'long long long' is too long for GC
PM   Вверх
Dem_max
Дата 20.7.2012, 04:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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





--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
NYX
Дата 20.7.2012, 05:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Спасибо! Читаю. Вот только что нарвался на эту серию статей еще http://www.sofmos.com/lyosha/Articles/multithreading1.html
Затарился пищей для ума. Читаю smile
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 20.7.2012, 11:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



NYX, код под Windows:
Код
EnterCriticalSection(cs);
...
LeaveCriticalSection(cs);
Код под Unix:
Код
pthread_mutex_lock(m);
...
pthread_mutex_unlock(m);
Видишь отличия? Кроме названий никаких. Поэтому, вход в критическую секцию - это захват мьютекса, выход - освобождение. И не важно, как ты это назовешь, суть не изменится. Поэтому, у тебя остается выбор из мьютексов и семафоров.

Семафоры имеет смысл использовать когда у тебя типичная схема из m производителей и n потребителей. Производители что-то делают, добавляют в очередь и сигнализируют семафором. Потребители ждут сигнала, берут из очереди и обрабатывают.

Мьютексы нужны тогда, когда несколько потоков что-то делают с одними и теми же данными, при этом как минимум один из них их меняет. В этом случае, каждый поток перед каждым обращением к общим данным должен захватить мьютекс, выполнить операцию и освободить его. Естественно, что для каждого блока данных должен быть свой мьютекс (общий для всех потоков, конечно).
PM   Вверх
NYX
Дата 20.7.2012, 19:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Ясно. А как быть с приоритетами? Допустим если поток записи более приоритетный, то есть его надо протиснуть в очередь сразу после ВЫПОЛНЯЮЩЕОСЯ не смотря на имеющуюся очередь из читателей? Вот везде описывается что такая возможность допустима... но никак не пойму, как это сделать. Это решается на уровне приоритетов ОС? То есть как вот приоритет для процесса устанавливается.... 

Это сообщение отредактировал(а) NYX - 20.7.2012, 19:04
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 20.7.2012, 20:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Процессы - это исполняющиеся экземпляры программ. А потоки - это составные части одного процесса. Не путай понятия.

Время блокировки нужно делать минимальным. Т.е. на время выполнения простейших операций добавления/извлечения данных из очереди. Поэтому в большинстве случае проблем не будет. Если же у тебя все так сильно нагружено, то копай в сторону lockless.
PM   Вверх
NYX
Дата 20.7.2012, 21:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Да, на счет процессов и потоков я знаю, процесс это своего рода набор потоков, где есть первичный поток и возможность создания дополнительных. По сути процесс это набор данных (оверхед). На счет нагрузки даже примерно сказать не могу smile так как не лету придумал модель такую и результат наверно только по реализации будет smile Очень интересно что получится smile может даже эта наработка и пригодиться когда нибудь. Кстати, вот та самая очередь входящих данных... от клиента... очередь должна быть FILO, но вот в чем беда. Как лушче его реализовать, alloc-функциями или new? smile пытался засечь время затраты с помощью clock() но почему то отследить разницу не удалось. Просто если делать его не FILO а FIFO то... это будет не целесообразно, так как стек будет обрастать шлаком, чт ов итоге может привести к переполнению. А в случае FILO с new это будет провацировать:
1) Удаление старого пункта задачи для пользователя и присабачивание нового
2) Если напор уж очень сильный, то просто напросто игнорировать.
Кроме того FILO не будет замедлять работу сервера в случае если в очереди имеется от 2х заданий. Так как непосредственный доступ к отдельным данным он наверно всеж допустим. Если использовать ВСЮ очередь как целое данное, то думаю ваще смысла нет FILO оно или FIFO.

А на счет приоритетов потоков... 
Sleep(0) пока не найдется нужный поток?  smile  Жестоко наверно...

Это сообщение отредактировал(а) NYX - 21.7.2012, 02:07
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 22.7.2012, 23:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Есть у меня подозрение, что ты путаешь FIFO и FILO. FILO - это стек (first in last out - первым пришел, последним уйдешь). Т.е. ты читаешь самые свежие данные, а самые старые могут лежать до скончания века. Стек нет смысла использовать в качестве очереди.
PM   Вверх
NYX
Дата 23.7.2012, 22:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



вот в том то и дело, что что это даже не стек, а фиксированная очередь, обслуживаемая несколькими потоками, для каждого отведена определенная часть очереди. Очередь фиксированная, ее размер позволяет определить степень загаженности, и если кол-во запросов от пользователя превышает очередь, следующие запросы игнорируются. На например, пользователь сломал мышку, она лаганула и 50 раз нажала кнопку ОТПРАВИТЬ smile все запросы улетят на сервер smile поток обработки входящих запросов отфильтрует их по времени, оставит только валидные запросы, из них может быть и 5 запросов подярдошных. Поток калькуляции начнет с обработки САМОГО СВЕЖЕГО запроса. Они как бы будут пропихиваться в очередь СНИЗУ, а поток калькуляции будет их извлекать СВЕРХУ. Я пока еще не знаю, но скорее всего такое реализовать для массива не получится. Хотя всякое может быть... я пока что не понял как можно обслужить такой массив запросов.
А кто нибудь может что-то сказать про TLS (тот что Thread Local Storage)? Что это такое ваще? smile

Это сообщение отредактировал(а) NYX - 23.7.2012, 22:07
--------------------
'long long long' is too long for GC
PM   Вверх
xvr
Дата 24.7.2012, 10:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Цитата(NYX @  23.7.2012,  22:03 Найти цитируемый пост)
А кто нибудь может что-то сказать про TLS

Могу сказать - забудьте про них пока  smile 
У вас задача (про потоки и обслуживание пользователей) от поста к посту видоизменяется быстрее, чем размножаются кролики  smile Вы уж как нибудь определитесь с конечными требованиями, а потом вам уже можно будет что нибудь и по делу посоветовать  smile 

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


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Цитата(NYX @  23.7.2012,  23:03 Найти цитируемый пост)
Они как бы будут пропихиваться в очередь СНИЗУ, а поток калькуляции будет их извлекать СВЕРХУ.
Это и есть FIFO (first in first out - раньше придешь, раньше уйдешь) - стандартный контейнер std::queue. Очередь (FIFO) она и есть очередь. А стек (LIFO или FILO) - это не очередь (контейнер std::stack), это хранилище данных с обратной очередностью извлечения.
PM   Вверх
NYX
Дата 25.7.2012, 01:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



вот что я имел ввиду ->

(новый) in -> ||||||||| -> out (старый)

Как бы поступает с начала и обслуживается с конца (или наоборот. Смысл один получаетсо smile)) Это даже скорее как конвеер. При наличии более 2х элементов, будет наименьшая дележка ресурсов потоками. Я это имел ввиду smile Я уже более менее въехал как ваще потоками пользоваться, образно уже легко представляю параллельные нити с ресурсами. На практике пока что только следовал примерам но все понятно что в них делается. Просто я еще не адаптировался к мышлению потоками, но в целом понял как и что smile 

Это сообщение отредактировал(а) NYX - 25.7.2012, 01:37
--------------------
'long long long' is too long for GC
PM   Вверх
volatile
Дата 25.7.2012, 01:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(NYX @  25.7.2012,  01:35 Найти цитируемый пост)
вот что я имел ввиду ->

(новый) in -> ||||||||| -> out (старый)

Это есть, первым пришел, первым уйдешь. FIFO

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


Бывалый
*


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

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



Блин, ну вот последовательность алгоритмическая:
1) Добавили новый элемент A
2) (возможно параллельно) Извлекли старый элемент Д
 smile ну он новый элемент не первым уйдет!!! Первым уйдет это как в стеке. Когда положил сверху, сверху он первым и ушел. А тут запихал снизу, а забрал сверху.  smile 

вот допустим, есть у нас цепочка тэ динамических элементов, где 0 элемент имеет указатель на следующий и предыдущий. Новым будет элемент тот, на который указывает element[0].pprev а старым будет element[9].pnext и вот пока один поток цепляет [0].pprev второй поток отцепляет [9].pnext (индексы элементов я поставил для условности чоб яснее было) smile Разве это FIFO? Если сделать что один поток цепляет [0].pnext а второй поток ждет пока первый завершит цепляние, потом по завершению захочет прочесть... а тут еще новый и еще... в итоге очередь будет расти в неимоверной прогрессии... и потоки будут драться за последнее слово. А если один пихает снизу, в этот момент ему не надо тормозиться, так как второй поток оперирует совсем другим, последним элементом. при кол-ве элементов в таком "конвеере", потоки не будут друг друга вытесянять smile вытеснение начнется когда кол-во элементов будет 1 smile тогда они уже будут может быть как то засыпать\просыпаться до момент освобождения ресурса smile Я еще пока не знаю можно ли такое вот реализовать в связке с сокетами и потоками... это вдвоейне жесть. Но гепотетически думаю реально. Я не знаю на сколько сильно будет грузить проц такая очередь + контроль ее размера (если на 1го клиента будет отделено напрмиер 200 элементов очереди) + сможет ли один поток справиться с этим. Счас эксперементирую с этим smile

Это сообщение отредактировал(а) NYX - 25.7.2012, 02:14
--------------------
'long long long' is too long for GC
PM   Вверх
volatile
Дата 25.7.2012, 02:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(NYX @  25.7.2012,  02:02 Найти цитируемый пост)
Разве это FIFO?

Да, это FIFO

PM MAIL   Вверх
NYX
Дата 25.7.2012, 02:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Черт побери, я был уверен что это нечто иное. Ну да ладно, главно суть теперь ясна. А что вы можете сказать о такой методе очереди для серверного ПО, в тех условиях где нет выделеного потока для каждого клиента, а клиенты делятся по группам, которые обслуживают потоки и на один поток приходится массив клиентов? Да и ваще, может я как неопытный, не вижу каких то подвохов в таком подходе?
Получается как...
* клиент приконнектилсо, ему выделилась очередь обладающая счетчиком контролирующим кол-во элементов очереди
* если клиент попадает в некую группу, его очередь располагается в потоке ГРУППЫ
* если клиент единственный для своей группы, или является грубо говоря нераспределенным пользователем, его очередь пихается в поток для непонятных клиентов (ну грубо говоря так). Если находится еще один клиент такой же группы, его к нему туда.. к первому АБСТРАКТНОМУ клиенту в поток, и поток уже обслуживает массив из двух очередей. в цикле из двух итераций пробегается по очередям, обрабатывает сначала 1го клиента, размещает в очередь на отдачу результата, потом второго клиента... и так далее.
Это не веб сервер это ваще хз чо за сервер... ну будем считать что это пусть будет допустим чат с залами для конференции. Блин наверно такое даже больше подходит.
* В контексте одного потока, данные очереди не могут обрабатываться другими, сторонними потоками. Это будет уже нелогично, если человек из конференции А напишит в конференцию Б smile Если челу из А надо написать кому то из Б, милости просим в зал Б smile соответственно, изолировать данные между потоками группы А и потоками группы Б нет необходимости. Поэтому, все что надо, каждому элементу такой очереди присвоить свой CRITICAL_SECTION (или сделать частью самого элемента, что было бы правильнее) и уже в потоке его использовать. Если дошло дело до того, что один элемент обрабатывают два потока (блин ну я тут имею ввиду контекст... немного не правильно. Контекст имел ввиду трех потоков как одного целого обрабатывающего механизма одной группы)... вот пытаются обратиться два потока одной группы к ПОСЛЕДНЕМУ и единственному элементу очереди, тогда соответственно какой то один поток получит доступ.... а точнее это и будет поток чтения очереди, потому что пока счетчик == 0 элементов нет. Как только счетчик > 0 - будим поток калькуляции.

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

есть разве что идея режимности сервера. Как например:
* режим 1 - сервер выполняет все три потока для группы
* режим 2 - сервер выполняет только прием \ отдачу
* режим 3 - сервер выполняет только калькуляцию (сердце формирования очереди отдачи + допустим фильтрация мата в чате)

И если надо наростить мощность... сервер 1го режима принимает в качестве определенной команды (может даже по удаленному терминалу) нечто вроди "rembind 192.168.1.2" и это делает следующее:
* очередь опустошается
* формируется новая очередь уже на новом калькуляторном сервере
* элегантно завершаются потоки калькуляции на первом сервере
* далее все дело функционирует на двух серверах, где время калькуляции обуславливается скоростью второго физического сервера который в свою очередь так же может давать запросы на сервер с БД

Какое ваще мнение на такую модельку? Даже пусть сложно, фиг с ним я не тороплюсь никуда, это просто эксперемент для себя smile

Это сообщение отредактировал(а) NYX - 25.7.2012, 02:56
--------------------
'long long long' is too long for GC
PM   Вверх
volatile
Дата 25.7.2012, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



NYX, ну очень сумбурно...  smile 

Цитата(NYX @  25.7.2012,  02:40 Найти цитируемый пост)
А что вы можете сказать о такой методе очереди для серверного ПО,

По возможности переполненя имхо, вообще по-барабану какой тип очереди. (FIFO или FILO)
Все зависит от соотношения помещающих и извлекающих потоков.
Защиту от переполнения нужно вводить в любом случае.

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

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

Вообще, общий совет: думайте больше о логичности, а не о быстродействии.
Ясно устроенный механизм, легче будет и оптимизировать. Но это уже потом, если будет на то необходимость.

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


Бывалый
*


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

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



Ну я тоже думаю что слишком уж заморочился. Просто как то диковато воспринимать факт динамической ячейки для очереди smile 
точнее переодического распределения памяти. А если допустим создать 10 ячеек, и оперировать как то может быть индексом (указателем элемента), может быть было бы быстрее smile На счет ясности и логики это да smile по мне лучше иметь большой код, но очень понятный, чем множество стремных конструктций с 280 символные строки содержащие всевозможные ухищрения языка smile
А на счет переполнения, я не ставил акцент на контроль переполнения smile просто наверно не так выразился. Мне кажется что описанная мною очередь будет немного прикольнее. Но все равно, все покажет только реализация с замерами времени выполнения \ быстродействия. В общем то сегодня я уже как второй день продолжаю изгаляться над кодом, даст бог, что то выйдет из этого полезного для меня smile В любом случае опыт важнее прежде всего smile

Это сообщение отредактировал(а) NYX - 25.7.2012, 14:17
--------------------
'long long long' is too long for GC
PM   Вверх
Alca
Дата 25.7.2012, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата

кстати почитай

http://forum.vingrad.ru/forum/topic-60076/view-all.html


--------------------
PM WWW ICQ Skype Jabber   Вверх
NYX
Дата 25.7.2012, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Спасибо. Читаю. Начало угнетающее smile
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 25.7.2012, 16:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Цитата(NYX @  25.7.2012,  03:02 Найти цитируемый пост)
Блин, ну вот последовательность алгоритмическая:
1) Добавили новый элемент A
2) (возможно параллельно) Извлекли старый элемент Д

Вот только откуда старый элемент Д взялся? Надо рассматривать с самого начала:
1. очередь пуста
2. в очередь добавлен элемент А
3. в очередь добавлен элемент Б
4. из очереди извлечен элемент А и добавлен В
5. из очереди извлечен элемент Б
...

Элемент А встал в очередь первым. И первым же ее покинул.
PM   Вверх
NYX
Дата 25.7.2012, 17:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Да именно так и есть smile все правильно smile
--------------------
'long long long' is too long for GC
PM   Вверх
NYX
Дата 29.7.2012, 21:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Ребят, допустимо ли такое использование критической секции?
Код

/******************************************************************************************************************************************************************************************************/
// Внешние включения
#include <windows.h>
#include <cstdio>

// Библиотечные включения
// ...

/******************************************************************************************************************************************************************************************************/
class some_object {
public:
    some_object() {
        InitializeCriticalSection(&CS);
    }
    ~some_object() {
        DeleteCriticalSection(&CS);
    }
    void out(char symbol) {
        EnterCriticalSection(&CS);
        for (unsigned int index = 0; index < 10; index++) {
            printf("%c", symbol);
            Sleep(1);
        }
        printf("\n");
        LeaveCriticalSection(&CS);
    }
    
private:
    CRITICAL_SECTION CS;
};

some_object ex;

unsigned long __stdcall thread(void *argument) {
    char *symbol = reinterpret_cast<char*>(argument);
    ex.out(*symbol);
    return 0;
}

/******************************************************************************************************************************************************************************************************/
int main(int argc, char** argv) {
    unsigned long ThreadID[2] = {0};
    void *ThreadHandle[2] = {NULL};
    char A = 'A';
    char B = 'B';
    ThreadHandle[0] = CreateThread(NULL, 0, thread, &A, 0, &ThreadID[0]);
    ThreadHandle[1] = CreateThread(NULL, 0, thread, &B, 0, &ThreadID[1]);
    WaitForMultipleObjects(2, ThreadHandle, true, INFINITE);
    return 0;
}
/******************************************************************************************************************************************************************************************************/

Не будет ли трудностей если два потока одновременно вызовут одну функцию одного объекта, при условии что внутри функции автоматически используется критическая секция?

Это сообщение отредактировал(а) NYX - 29.7.2012, 21:46
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 29.7.2012, 22:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



NYX, собственно именно для этого критические секции и существуют.
Рекомендую тебе использовать RAII для организации критических секций:
Код
Mutex mutex;
...
{
  Mutex::Lock lock(&mutex); //вызвался конструктор Mutex::Lock, который осуществил вход в критическую секцию
  //находимся внутри критической секции
  ...
} //вызвался декструктор класса Mutex::Lock, который завершил критическую секцию
Эта технология используется во всех современных библиотеках С++. В частности, в стандарте C++11: std::mutex и std::lock_guard.
PM   Вверх
SVN74
Дата 29.7.2012, 22:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Простите, если я не правильно понял схему желаемого сервера, но я бы сделал так:
Создал класс в  котором прикрепил 1  - "map" - для базы клиентов,  2 - сокетный протокол (сервер, клиент), 3 - сохранения баз данных.
Затем это все размножил бы класс по количеству групп, - дав каждой группе свой порт ожидания.
В итоге получиться независимые группы со своими серверами и базами данных без необходимости синхронизаций... 

Добавлю:
Тоже самое можно создать и на одном ожидающем порту, только потом разбрасывать каждому классу отдельно его клиента, но тут уже надо будет одну синхронизужку  делать..


Это сообщение отредактировал(а) SVN74 - 29.7.2012, 22:22
PM MAIL WWW   Вверх
NYX
Дата 29.7.2012, 22:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Можно было бы вообще группы клиентов разбить на процессы отдельные. Но, допустим челу надо скаконуть из одноу группы, чонить написать и смотаться в другую.... группы динамические и основной акцент на скорость их формирования. Можно было бы выделять например 2-4 пустые группы, в случае чего юзвери туда могли бы прошмыгнуть создав новую. Переход в уже готовую группу (где есть участники, не темперную) производился бы просто под средством присваивания пары указателей smile то есть, имеется всего изначально, дву группы:
А) нераспределенные пользователи (общий чат)
Б) группа (конференция)

Группа А всего одна и из нее юзвери переводятся в любую из множества групп Б. Сам переход обуславливается присваиванию указателей на ЧАСТЬ очереди, которую надо обработать в потоках группы. То есть переход, есть не что иное как "ткнуть поток носом в миску, откуда лакать.". Если речь идет о новой группе... она как бы и есть но ее как бы и нет. То есть, создание группы условно говоря это когда боле 1го собеседника находятся в общей комнате. Сама общая комната разумеется делается по запросу. Запрос выглядит примерно так "отцепи меня от нераспределенной группы и сделай отдельной группой вон с тем чуваком". Создается новых трипотока куда заведомо посылаются указатели на область очереди 2х собеседников. Очередь есть не что иное как глобальный массив стеков. Он есть до тех пор, пока есть пользователь. То есть основная нагрузка падает только на создание потоков обслуживания:
* вход. трафик
* калькуляция
* выход. трафик
Но блин я хз как масштабируемость делать. Как можно с такой схемой распределить нагрузку. Пока что на заметке у меня memory-maped file, но я еще не знаю можно ли использовать удаленно их и вообще выгодно ли это. Если это не выгодно, то кирдык-бабай. Если авалибл, то тогда шаровый мемори-мэпед файл, деление сервера на 2 составляющих
1) обработка i\o очередей (стеков)
2) калькуляция ->
3) база данных (ну это еще хз нужна ли она для чата, но пусть будем считать что нужна для хранения последних нцати сообщений, что бы вновь прибывшие смогли прочитать их при джоинте)

каждый из пунктов является отдельным VPS (наверно на физическом уровне).

Блин а еще вот я так думаю, сколько еще ждать до момент MinGW в стандарте С++11 smile у меня уже слюни текут при зачтении новых возможностей STL! Читаю и плачу томными ночами в ожидании нового компилятора.

Это сообщение отредактировал(а) NYX - 29.7.2012, 22:38
--------------------
'long long long' is too long for GC
PM   Вверх
SVN74
Дата 29.7.2012, 22:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(NYX @  29.7.2012,  22:36 Найти цитируемый пост)
Блин а еще вот я так думаю, сколько еще ждать до момент MinGW в стандарте С++11  у меня уже слюни текут при зачтении новых возможностей STL! Читаю и плачу томными ночами в ожидании нового компилятора.

 smile 
И все же какова тогда выгода от группирования, если клиенту необходимо давать доступ к другой группе.
Может тогда и клиента размножить на  несколько групп одновременно?

По моему мнению, - группы на то и группы, чтобы не контактировать...


Это сообщение отредактировал(а) SVN74 - 29.7.2012, 22:48
PM MAIL WWW   Вверх
NYX
Дата 29.7.2012, 22:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Про RAII - я мальца сократил код. Ваще где то подглядел обертку для критсекций, там в конструкторе делается инициализация, в дуструкторе соответственно...  публики лок, трайлок, анлок. В реальном счас исходнике у меня эта обертка трудится. Создается некий объект, пусть это будет отображение чего-то там где то в консольке и к этому объекту имеется доступ с двухнцати потоков. И внутри потока уже нет необходимости делать эти постоянные вызовы. В пространстве объекта уже есть обертка которая используется во всех потенциально-потокововызываемых функциях. Но меня немного смутило (Опять таки я дуб в низкоуровневом, постепенно вникаю по мере возможности, но отдельно изучению отладке время не уделяю) то что функция объекта одна и вызов функции двойной, а вот тело функции уже лок-анлок. (очень коротко сказал). просто в случае критсекций в потоке, получается как, не выполняется тело потока (потоки ведь разные экземпляры функций и тел или один и тот же тел?) и именно тело лочится. А в случае функции объекта, это уже ... одна и та же получается. Я только в этом усомнился. В целом, если я предполагаю что использовать такие возможности допустимо, то наверно я вкурил в эту тему smile Что то еще блин сказать хотел...

Добавлено @ 22:49
Клиента размножать?... ну ваще длительность потоков она наверно более высока нежели длительность многоликости клиента. Хотя... Я ваще не хочу создавать много потоков. Блин это отстой. Но я пока не подкован в потоках и не знаю какие сложности в производительности возникнут. Я еще краем уха слышал что потоки можно привязать к N процессору. Так ли это? Реализуемо ли это на WinAPI? Я так и не понял. Буду искать.

Если размножать клиента, то тогда ваще можно использовать от силы несколько потоков, для групп и нераспределенных юзверей. Тогда все будет диктоваться объектом очереди, где уже будет указано кто есть who  smile и так же для двух типов пользователей используется свое перечисление пользователей, в котором могут будлироваться юзвери обоих групп.

Это сообщение отредактировал(а) NYX - 29.7.2012, 22:55
--------------------
'long long long' is too long for GC
PM   Вверх
SVN74
Дата 29.7.2012, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



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

PM MAIL WWW   Вверх
NYX
Дата 29.7.2012, 22:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



На одном потоке тоже было бы круто, но... мне не принципиальны потоки. Я так опнимаю самое главное это масштабируемость сервера и грамотное распределение нагрузки и лучше ваще автоматизированное. Если это возможно на одном потоке? Хм, быть одному потоку. Просто если потоков много, и юзвери допустим молчат, поток замораживается. В этом и прелесть. А однопоточное ПО оно будет безконца парсить очереди на предмет наличия. Либо так же создавать флаги наличия позиций очереди...

Это сообщение отредактировал(а) NYX - 29.7.2012, 22:58
--------------------
'long long long' is too long for GC
PM   Вверх
SVN74
Дата 29.7.2012, 22:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(NYX @  29.7.2012,  22:57 Найти цитируемый пост)
На одном потоке тоже было бы круто, но... мне не принципиальны потоки. Я так опнимаю самое главное это масштабируемость сервера и грамотное распределение нагрузки и лучше ваще автоматизированное. Если это возможно на одном потоке? Хм, быть одному потоку. 

А сколько будет предположительное количество  клиентов одновременно работать?

PM MAIL WWW   Вверх
NYX
Дата 29.7.2012, 23:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Пальцем в небо - тысяща кляентоф :] но опять же, что делать с наплывом зомбочатеров? Вдруг народу захочется поболтать, куда их посылать? Мимо или на размножаемые серверы с логин-сервера? или как васче делать то? Если бы я знал как организовать шаровые ресурсы между двумя физическими серверами при условие что шаровые данные будут под треды и разделяемыми... знать-бы вот...
--------------------
'long long long' is too long for GC
PM   Вверх
SVN74
Дата 29.7.2012, 23:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(NYX @  29.7.2012,  23:02 Найти цитируемый пост)
Пальцем в небо - тысяща кляентоф :] 

 smile 
Та Вы что ? 
Забудьте о многопотоковости, это для Вас убийство, только неблокирующий сокет и общая база...
Максимум 200 клиентов можно гонять по потокам, а если выше, только через один неблокирующий поток...

Это сообщение отредактировал(а) SVN74 - 29.7.2012, 23:10
PM MAIL WWW   Вверх
bsa
Дата 29.7.2012, 23:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Цитата(NYX @  29.7.2012,  23:46 Найти цитируемый пост)
Про RAII - я мальца сократил код.
причем тут RAII?
Цитата(NYX @  29.7.2012,  23:46 Найти цитируемый пост)
 Ваще где то подглядел обертку для критсекций, там в конструкторе делается инициализация, в дуструкторе соответственно...

Молодец. Теперь подсмотри где-нибудь обертку, которая производит таким же образом еще и захват с освобождением мьютекса. Например, в бусте.
PM   Вверх
NYX
Дата 29.7.2012, 23:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Если так, стиснув зубы... VPS и размножение на многих провах оно как бы, ну платное что ли. И допустим изначально гонять несколько отдельных серверов накладно, при том что кол-во пользователей может снижаться и варьироваться. А если бы например сделать на трех потоках для групп, то тогда можно было бы ОДНО И ТО ЖЕ ПО запускать уже в трех режимах.
1) как у же помоему писал - полноценный сервер
2) сервер в режиме прием-отдача
3) сервер калькуляций (операция с БД, проверка на содержание мата и прочее прочее)
В этом случае, получается цепь

TI - thread in
TC - thread calc
TO - thread out
QI - queue in
QO - queue out

1) TI -> QI -> TC -> OQ -> TO
2) TI -> QI ... ... ... OQ -> TO
3) ... ... QI -> TC -> OQ ... ...
тогда скорость калькуляции была бы быстрее. Для пунктов 2 и 3 очереди были бы шаровыми, может и по экземпляру очереди на сервак, а может располагались бы например QI на 2, а OQ на 3. Но это единственное до чего я смог догадаться smile

Добавлено @ 23:12
bsa
Цитата

Молодец. Теперь подсмотри где-нибудь обертку, которая производит таким же образом еще и захват с освобождением мьютекса. Например, в бусте.

Брр. В смысле? не, ну мьютек принципиально... ща-ща. Неявным образом захват мьютекса это будет создание объекта и деструктор уже будет выполняться по итогу выполнения функции. Окей... моя обертка работает так же smile но только это работабельно в случае мьютекса уже имеющегося глобально. В случае критсекции это уже внутри объекта использующего объект обертки. Про RAII читал тут http://www.gamedev.ru/code/terms/RAII
Я понял в чем смысил. Если честно это очень здоровски использовать такие пряники. Так как можно создать весьма не сложные потокобезопасные объекты. А может даже и вообще сделать так, что бы все разделяемости делались закулисами.

Это сообщение отредактировал(а) NYX - 29.7.2012, 23:23
--------------------
'long long long' is too long for GC
PM   Вверх
NYX
Дата 29.7.2012, 23:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



А в бусте в каком направлении смотреть? 
Код

    template<typename SharedMutex>
    class shared_lock_guard
    {
    private:
        SharedMutex& m;

    public:
        typedef SharedMutex mutex_type;
        BOOST_THREAD_NO_COPYABLE(shared_lock_guard)
        explicit shared_lock_guard(SharedMutex& m_):
            m(m_)
        {
            m.lock_shared();
        }
        shared_lock_guard(SharedMutex& m_,adopt_lock_t):
            m(m_)
        {}
        ~shared_lock_guard()
        {
            m.unlock_shared();
        }
    };


Это сообщение отредактировал(а) NYX - 29.7.2012, 23:38
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 30.7.2012, 10:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Цитата(NYX @  30.7.2012,  00:35 Найти цитируемый пост)
А в бусте в каком направлении смотреть? 

boost::thread. Там есть класс mutex (ты его называешь критической секцией, - очень жаль, что ты меня так и не понял и пытаешься использовать везде термины windows).
PM   Вверх
NYX
Дата 30.7.2012, 17:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



да я уже глянул исходники, я понял смысл. передается объект в конструктор и по завершению работы функции срабатывает деструктор который этот самый мутекс и освобождает smile
В плане не понял? Про критсекции? Я знаю что это не мутексы и ваще это некий гибрид. У критсекций минус есть, они не могут быть доступны из других процессов. Поэтому критсекции удобно использовать для каких то внутренних атомарностей объектов. Если речь идет о шаровых данных, то мутексы \ семафоры удобнее, так как с их помощью можно добиться немного более лучшего эффекта, нежели выстраивание потоков в ряд.

Это сообщение отредактировал(а) NYX - 30.7.2012, 17:49
--------------------
'long long long' is too long for GC
PM   Вверх
NYX
Дата 30.7.2012, 18:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



концептуально читатели-писатели на мьютексахЪ

Это сообщение отредактировал(а) NYX - 30.7.2012, 19:01

Присоединённый файл ( Кол-во скачиваний: 2 )
Присоединённый файл  MultiCore_OS_Lab2_ReadersWriters.pdf 423,53 Kb
--------------------
'long long long' is too long for GC
PM   Вверх
NYX
Дата 30.7.2012, 19:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Семафоры, мониторы и синхронные сообщения

Присоединённый файл ( Кол-во скачиваний: 1 )
Присоединённый файл  MultiCore_OS_Lec4_Concurrency2.pdf 423,56 Kb
--------------------
'long long long' is too long for GC
PM   Вверх
bsa
Дата 30.7.2012, 22:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

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



Цитата(NYX @  30.7.2012,  18:44 Найти цитируемый пост)
В плане не понял? Про критсекции? Я знаю что это не мутексы и ваще это некий гибрид. У критсекций минус есть, они не могут быть доступны из других процессов. Поэтому критсекции удобно использовать для каких то внутренних атомарностей объектов. Если речь идет о шаровых данных, то мутексы \ семафоры удобнее, так как с их помощью можно добиться немного более лучшего эффекта, нежели выстраивание потоков в ряд.

Ты опять меня не понимаешь. Такое ощущение, что ты не читаешь что я тебе пишу. А видишь только ряд ключевых слов, но смысл предложений до тебя не доходит.
Читай внимательно: В WINDOWS КРИТИЧЕСКОЙ СЕКЦИЕЙ НАЗЫВАЕТСЯ ТО, ЧТО ВЕЗДЕ НАЗЫВАЕТСЯ МЬЮТЕКСОМ. Именно поэтому, термин "критическая секция" лучше вообще не употреблять, кроме как в контексте WinAPI (именно на уровне реализации, а на уровне обсуждения стратегий и алгоритмов следует использовать mutex).

Это сообщение отредактировал(а) bsa - 30.7.2012, 22:06
PM   Вверх
NYX
Дата 31.7.2012, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



bsa,  вот всегда так. Я тебя прекрасно понял и написал аж несколько раз что критсекция в моем понимании это гибрид и что изначально есть мьютексы, семафоры дейкстры и многое другое smile Критические секции удобно использовать в определенных ситуациях... само собой для нативного windows-ПО. В кроссплатформенном ПО не целесообразно smile Я рассуждаю с акцентом на Windows потому что под Linux или какую либо другую ОС я пишу.  smile Я безусловно благодарен за такое разъяснение! Если бы не ваши усилия, я бы мало чего смог понять! Поэтому всем кто отвечал в теме, каждомму по плюсу, а то и несколько! smile

Это сообщение отредактировал(а) NYX - 31.7.2012, 10:54
--------------------
'long long long' is too long for GC
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.2961 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


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

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