Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

EnterCriticalSection

354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
Доброго времени суток всем. :)

ситуация такая, есть ресурс, есть несколько потоков(>2) претендующих на этот ресурс, простой пример:
Код:
#include <windows.h>
#include <iostream>
#include <queue>

using namespace std;

queue<DWORD> cs_queue;
queue<DWORD> th_queue;

class Mng
{
public:
    Mng()
    {
        InitializeCriticalSection(&m_CS);
    }

    ~Mng()
    {
        DeleteCriticalSection(&m_CS);
    }

    void process()
    {
        EnterCriticalSection(&m_CS);
        cs_queue.push(GetCurrentThreadId());
        Sleep(200); // имитация какой-то работы
        LeaveCriticalSection(&m_CS);
    }
    CRITICAL_SECTION m_CS;
};

Mng mng;

DWORD WINAPI thread(void * v)
{
    th_queue.push(GetCurrentThreadId());
    mng.process();
    return 0;
}

int main()
{
    DWORD dw1 = 0;
    CreateThread(0, 0, thread, 0, 0, 0);
    CreateThread(0, 0, thread, 0, 0, 0);
    CreateThread(0, 0, thread, 0, 0, 0);
    CreateThread(0, 0, thread, 0, 0, 0);
    CreateThread(0, 0, thread, 0, 0, 0);
    CreateThread(0, 0, thread, 0, 0, 0);
    CreateThread(0, 0, thread, 0, 0, 0);
    CreateThread(0, 0, thread, 0, 0, 0);
   
    Sleep(4000); // ждем завершения всех потоков (можно через WaitForMultipleObjects)
   
    cout << "threads queue" << endl;
    while(!th_queue.empty())
    {
        cout << th_queue.front() << " ";
        th_queue.pop();
    }
    cout << endl << "cs queue" << endl;
    while(!cs_queue.empty())
    {
        cout << cs_queue.front() << " ";
        cs_queue.pop();
    }
    getchar();
    return 0;
}

в общем, запускаю просто программку, списки сходятся.
запускаю через F5 в студии, без всяких точек останова и т.д. - списки не сходятся.
Как работает EnterCriticalSection, и стоит ли изобретать велосипед:
- lock() - ставить потоки в очередь на ожидание(SuspendThread),
- unlock() - выбирать из очереди и размораживать их (ResumeThread)
?
заранее спасибо за любую помощь. :)
505
18 января 2008 года
vAC
343 / / 28.02.2006
В таком случае два объекта-ресурса: cs_queue и th_queue. Первый синхронизируете, второй - нет. Отсюда всякая ерунда.
А то, что в каком-то случае работает, а в каком-то не работает - всего лишь последствие ошибки в программе. В таких случаях не следует привязываться к подобным фактам, и тем более, не искать ошибок в компиляторах и средах разработки. Необходимо сначала разобраться в своем коде.

p.s. почитайте что-нибудь по ключевым словам "STL Thread Safety", возможно, надежда была на безопасность со стороны STL...
Ничего подобного с Suspend и Resume творить не надо, шаблон замка прекрасно реализуется с помощью той же критической секции. Ну а если уж совсем не изобретать велосипед, то пользуйтесь boost.
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
нет, здесь cs_queue и th_queue - вроде бы как и есть "thread safe" :)
cs_queue и th_queue я использую чтобы смотреть порядок вхождения потоков в секцию и выполнения кода.
вот здесь:
 
Код:
Sleep(200); // имитация какой-то работы

должна быть работа с каким-то общим ресурсом.
идея такова: потоки стали в очередь для выполнения функции process(), и по одному из этой очереди в ПРАВИЛЬНОМ ПОРЯДКЕ должны выходить и выполнять этот process().
я воспользовался критическими секциями для синхронизации. и у меня как-то нарушается порядок выполнерия - я написал..
 
Код:
что делать?

хотелось бы не приплетать сторонние библиотеки...
505
18 января 2008 года
vAC
343 / / 28.02.2006
А вот и не thread safe. В обоих случаях происходит запись в контейнер.

 
Код:
DWORD WINAPI thread(void * v)
{
    th_queue.push(GetCurrentThreadId());
    mng.process();
    return 0;
}


Цитата:

MSDN: Thread Safety in the Standard C++ Library

The container classes are vector, deque, list, queue, stack , priority_queue, valarray, map, multimap, set, multiset, basic_string, bitset.
...
For writes to the same object, the object is thread safe for writing from one thread when no readers on other threads
...

354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
ой.
а как мне организовать очередность потоков для ресурса?
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
и почему тогда обе очереди сходятся если запускать без отладчика?
505
18 января 2008 года
vAC
343 / / 28.02.2006
Организовать точно также как для cs_queue. То что обе очереди сходяться - всего лишь везение (или наоборот, т.к. такие ошибки потом тяжело искать)
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
блин :D
эти очереди я сделал только чтобы сверить очередность вхождения и выхождения из секции, были кой-какие проблемы..
-
меня интересовало - СЕКЦИЯ не меняет последовательность претендующих потоков? дело в том что я встретил какую-то бурду про секцию и она меня жутко смутила.
:D
все это похоже на бред конечно, но в литературе ничего не написано про очередность потоков... а я сам я и не знаю у кого спросить.
505
18 января 2008 года
vAC
343 / / 28.02.2006
Цитата: ШпиЁн
блин :D
эти очереди я сделал только чтобы сверить очередность вхождения и выхождения из секции, были кой-какие проблемы..
-
меня интересовало - СЕКЦИЯ не меняет последовательность претендующих потоков? дело в том что я встретил какую-то бурду про секцию и она меня жутко смутила.
:D
все это похоже на бред конечно, но в литературе ничего не написано про очередность потоков... а я сам я и не знаю у кого спросить.



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

354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
я пишу программку, критичную к времени выполнения и последовательности исполнения потоков, активно использующий некий общий ресурс. код потоков - РАЗНЫЙ. (здесь для простоты я привел одинаковый)

собственно, прежде чем биться головой об написание какого-то своего метода синхронизации, хотелось узнать может в системе такое уже есть? :)
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
простой пример:
поток1 захватил секцию и выполняется(долго).
через некоторое время поток2 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток3 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток4 подготовил данные и ожидает в EnterCriticalSection()
поток1 освобождает секцию, в вместо потока2 в защищенную область попадает поток4.

вот чтобы такого не было... секции гарантируют правильную последовательность?
505
18 января 2008 года
vAC
343 / / 28.02.2006
Что значит "критична к последовательности исполнения потоков"? Имеется ввиду то, что некоторый участок кода должен быть выполнен заданным набором потоков по-порядку? Тогда это не стыкуется с тем, что код потоков разный.

Что касается общего ресурса:
Ваша задача - обеспечить безопасную работу с некоторым ресурсом.
Ресурс ваш можно инкапсулировать в некий класс и обеспечить интерфейс для безопасного взаимодействия с ним. В реализации интерфейса делайте синхронизацию там, где это необходимо.
505
18 января 2008 года
vAC
343 / / 28.02.2006
Цитата: ШпиЁн
простой пример:
поток1 захватил секцию и выполняется(долго).
через некоторое время поток2 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток3 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток4 подготовил данные и ожидает в EnterCriticalSection()
поток1 освобождает секцию, в вместо потока2 в защищенную область попадает поток4.

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



Зачем вам эта гарантия, когда нет гарантии, что потоки встанут в очередь на вход в секцию в определенном порядке? Может будет так:
поток4 захватил секцию и выполняется(долго).
через некоторое время поток1 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток3 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток2 подготовил данные и ожидает в EnterCriticalSection()

1
18 января 2008 года
kot_
7.3K / / 20.01.2000
Цитата: ШпиЁн
простой пример:
поток1 захватил секцию и выполняется(долго).
через некоторое время поток2 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток3 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток4 подготовил данные и ожидает в EnterCriticalSection()
поток1 освобождает секцию, в вместо потока2 в защищенную область попадает поток4.

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


Нет не гарантируют. Именно для этого в ОС и существуют объекты синхронизации позволяющие упорядочивать доступ к общим ресурсам. Секции могут гарантировать что к ресурсу получает достут только один из потоков - последовательность доступа гарантировать они не могут.

354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
Цитата: vAC
Что значит "критична к последовательности исполнения потоков"? Имеется ввиду то, что некоторый участок кода должен быть выполнен заданным набором потоков по-порядку?


не совсем. код потоков разный, ресурс - например глобальный объект, какого-нибудь класса.
--

Цитата: vAC
Ресурс ваш можно инкапсулировать в некий класс и обеспечить интерфейс для безопасного взаимодействия с ним. В реализации интерфейса делайте синхронизацию там, где это необходимо.


я создал базовый класс с методами lock() и unlock() - традиционно :)
--
отказаться от выполнения последовательности не могу - условие.
--
как реализовать такую синхронизацию потоков? пусть даже без критических секций?

354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
Цитата: kot_
Именно для этого в ОС и существуют объекты синхронизации позволяющие упорядочивать доступ к общим ресурсам.

пример неплохо бы...
InterlockedPushEntrySList и т.д.?

354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
Цитата: vAC
Зачем вам эта гарантия, когда нет гарантии, что потоки встанут в очередь на вход в секцию в определенном порядке? Может будет так:
поток4 захватил секцию и выполняется(долго).
через некоторое время поток1 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток3 подготовил данные и ожидает в EnterCriticalSection()
через некоторое время поток2 подготовил данные и ожидает в EnterCriticalSection()


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

505
18 января 2008 года
vAC
343 / / 28.02.2006
Можно предложить такую схему:

1. если выполняется поток1, то выполнить код, установить сигнал1
2. если выполняется поток2, то ждать сигнал1, выполнить код, установить сигнал2
3. если выполняется поток3, то ждать сигнал2, выполнить код, установить сигнал3
...

Сигнал можно реализовать скажем событием.
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
потоков может быть очень много, на каждый получается сигнал? нужна очередь сигналов для потоков? WaitForSingleObject работает медленнее чем секции.
-
потоки реализуют работают с бд. поэтому последовательность важна. :)
-
я сделал так:
есть флаг зянят/свободен.
поток входит в lock() - проверяется флаг,
если свободен - ставим занятым, продолжаем выполнение. если занят - поток ставится себя в очередь, и вызывается SuspendThread для себя.(засыпает на этом месте)

поток входит в unlock() - поток смотрит есть ли в очереди замороженных потоков кто-либо. если есть - достаем его и вызывает ResumeThread для него. если очередь пуста - ставим флаг - свободен.
_
классический алгоритм вроде. :)
но deadlock'и случаются постоянно. (т.к. очередь тоже нужно синхронизировать и т.д.)
_
ЧТО ДЕЛАТЬ?
505
18 января 2008 года
vAC
343 / / 28.02.2006
То же самое можно сделать и с критическими секциями, но это будет менее выразительная реализация: Сигнал моделируется покиданием секции. А ожидание - заходом в нее.
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
т.е. много секций, на кадый поток - секция? так ведь возможна взаиманая блокировка и все такое... или я неправильно понял?
505
18 января 2008 года
vAC
343 / / 28.02.2006
0. для каждого i: поток i входит в секцию секцияi
0.5 сбор потоков в точке
1. если выполняется поток1, то выполнить код, покинуть секцию1
2. если выполняется поток2, то войти в секцию1, выполнить код, покинуть секцию2
3. если выполняется поток3, то войти в секцию2, выполнить код, покинуть секцию3
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
я наверное чего-то непонимаю.

если выполняется поток1, то выполнить код, покинуть секцию1
а если в этот момент на секцию 1 станет второй поток и будет ждать, дождется и полезет выполнять. нет?

можно пожалуйста, хоть схематично программу набросать?
505
18 января 2008 года
vAC
343 / / 28.02.2006
выполнять действия "покинуть секциюi" нужно, разумеется, после самого выполнения кода, после этого покидаем и второй поток может спокойно заходить, а до этого момента она заблокирована (пункт 0), но тут тоже проблема - необходимо будет собрать потоки в точке, прежде чем начинать выполнение кода, иначе секция не будет заблокирована и какой-нибудь поток проникнет в критический код.
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
дубль два:

если выполняется поток1, то выполнить код, покинуть секцию1
а если в этот момент на секцию 1 станет второй поток и будет ждать, дождется и полезет выполнять. нет? а если третий станет в ожидание, а если четвертый, и все на секции1 :D а где гарантия что секция их отпустит так как они стали? :)
505
18 января 2008 года
vAC
343 / / 28.02.2006
Цитата: ШпиЁн
дубль два:

если выполняется поток1, то выполнить код, покинуть секцию1
а если в этот момент на секцию 1 станет второй поток и будет ждать, дождется и полезет выполнять. нет? а если третий станет в ожидание, а если четвертый, и все на секции1 :D а где гарантия что секция их отпустит так как они стали? :)



Со вторым потоком все правильно, это же и требуется? Первый выполняет задачу, после ее завершения выполняется второй поток.
А третий станет не на секция1, а на секция2, которая освободиться только после завершения работы потока2. Аналогично с 4-й, 5-й. Я просто смоделировал сигнал критической секцией, то же самое можно сделать событием, защелкой...
Подправил схему, не совсем конечно понятно сформулировал

354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
где гарантия что секция1 отпустит именно поток2, а не поток3 или поток4, ведь стоят там ВСЕ?
если не сильно занят, пожалуйста, набросай код хоть какой-нибудь.
505
18 января 2008 года
vAC
343 / / 28.02.2006
Так я же писал если, а это значит, что дальнейшее будет выполняться только для конкретного потока, т.е. поток 3,4,5... не будут заходить в секция1.
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
:)
а если будут. что их остановит? :D
все равно большое спасибо за идею. :)
505
18 января 2008 года
vAC
343 / / 28.02.2006
Примерно так:
 
Код:
if (thread == 2) Enter(section1)
if (thread == 3) Enter(section2)
if (thread == 4) Enter(section3)
<выполняем код>
if (thread == 1) Leave(section1)
if (thread == 2) Leave(section2)
if (thread == 3) Leave(section3)
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
пусть пришел поток thread = 2; вошел в секцию section1.
потом пришел поток thread = 3, проверились условия и он спокойно вошел в секцию section2, и полез к данным, которые еще заняты потоком thread = 2. разве нет?
_
секции: ОДНА секция блокирует НЕСКОЛЬКО потоков(кроме одного), если эти НЕСКОЛЬКО потоков захотят в нее войти.

в этом алгоритме потоки вообще не пересекаются на одной секции.
505
18 января 2008 года
vAC
343 / / 28.02.2006
нет, для того чтобы такого не происходило есть пункт 0 (просто я его не включил в код :)), который изначально блокирует ВСЕ секции. Второй поток не зайдет до тех пор, пока первый не выйдет из секции и ОДНА секция блокирует только ОДИН поток, создается нечто похожее на цепочку: одно звено не держит все остальные, а только соседнее.
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
подробнее, пожалуйста, об этом нулевом шаге :)
КАК блокирует? Enter во все секции? освобождение опять же может быть в проивзольном порядке? :)

синхронизация синхронизации :)

пожалуйста, если можно, весь код :)
354
18 января 2008 года
ШпиЁн
468 / / 19.02.2006
есть много алгоритмов lock-free и wait-free на основе атомарных операций, но КАК их реализовать? может у кого есть примеры...
398
19 января 2008 года
Alexandoros
630 / / 21.10.2005
Подход неверен в корне.

Что мы имеем - ресурс, к которому по_определенной_очереди должен выполнятся доступ.

То есть имеем 1(один) поток (назовем его П1) и последовательность действий, с приоритетами, которые П1 должен выполнить. Значит так и делаем - в std::set(чтоб отсортировано) твои потоки пихают номер действия (через критсекцию) и выставляют евент "появился новый запрос". П1 оживает от евента, и выбирает (через критсекцию) номер первого действия из сета (как помним, они у нас упорядоченные). И выполняет его.

Все.

А ты пытаешся прикрутить 5е колесо к лодке.
398
19 января 2008 года
Alexandoros
630 / / 21.10.2005
Цитата:
есть много алгоритмов lock-free и wait-free на основе атомарных операций


атомарные операции - группа ф-ций Interlocked... (InterlockedIncrement etc)

354
19 января 2008 года
ШпиЁн
468 / / 19.02.2006
Цитата: Alexandoros
Подход неверен в корне.

Что мы имеем - ресурс, к которому по_определенной_очереди должен выполнятся доступ.

То есть имеем 1(один) поток (назовем его П1) и последовательность действий, с приоритетами, которые П1 должен выполнить. Значит так и делаем - в std::set(чтоб отсортировано) твои потоки пихают номер действия (через критсекцию) и выставляют евент "появился новый запрос". П1 оживает от евента, и выбирает (через критсекцию) номер первого действия из сета (как помним, они у нас упорядоченные). И выполняет его.

Все.

А ты пытаешся прикрутить 5е колесо к лодке.



претендующих на ресурс потоков может быть до нескольких сотен. и КАЖДЫЙ поток хочет выполнить только ОДНО действие над общим ресурсом.(потоки должны выполняться в правильной последовательности. :)) нужно создать один управляющий поток что ли? пожалуйста можно подробнее?

354
19 января 2008 года
ШпиЁн
468 / / 19.02.2006
Цитата:
есть много алгоритмов lock-free и wait-free на основе атомарных операций
атомарные операции - группа ф-ций Interlocked... (InterlockedIncrement etc)

это я знаю. алгоритм CAS - CompareAndSwap, функции InterlockedCompareExchange. я про то что нигде не мог найти примера реализации :(

398
20 января 2008 года
Alexandoros
630 / / 21.10.2005
Цитата:
я про то что нигде не мог найти примера реализации


asm lock xchg eax,ebx


Цитата:

претендующих на ресурс потоков может быть до нескольких сотен. и КАЖДЫЙ поток хочет выполнить только ОДНО действие над общим ресурсом.(потоки должны выполняться в правильной последовательности. ) нужно создать один управляющий поток что ли?


Да хоть 2к. Да, создавай один рабочий поток.

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

Что конкретно непонятно?

354
21 января 2008 года
ШпиЁн
468 / / 19.02.2006
во, теперь понято. :) спасибо :)
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог