Здравствуйте, _Morpheus_, Вы писали:
_M_>lock и WaitOne() это одно и тоже — и то и другое отдает процессорное время системе для других потоков...
Да, но только поведение после того, как поток дождался — разное. Для lock'а начинается волнение кода, который он "защищает", а для Manual(Auto)ResetEvent — можн делать что сам захочешь.
А>>Частично (в функции) — да. Но повотрю еще раз — если функция выполняется одним потоком, и в это время вызвана другим потоком, он должен просто дождаться ее завершения. И ВСЕ. Из ждущего потока функция вызвываться не должна.
_M_>из ждущего потока функция вызываться не может по определению, т.к. ждущий поток спит — у него нет процессорного времени чтобы вызвать функцию...
Это я понимаю. Просто слово выбрать тяжело было. Там имелось ввиду "из потока, который ожидал и дождался"
А>>Частично это так и сделано. Только, как я уже говорил, если функция будет вызвана из другого потока во время ее выполения, этот поток не просто дложен получить null и успокоиться, а ждать на ManualResetEvent, который будет выставлен в Set cамой функцией по окончании своей работы.
_M_>тогда вам такой подход не нужен, вам нужен обычный lock, без всяких возвратов null
Покажи как
А>>Вы мне сказали, что это нужно делать при помощи Monitor.PulseAll, только вот его я здесь и не вижу
_M_>да точно также как с событием, только вместо вызова Set, вызывать нужно PulseAll — это аналог Set, Reset, но с той разницей что проснутся все потоки ожидающие освобождения заданного объекта
Буду оч признателен если покажешь на примере
Кроме того, см. плз мой ответ mihailik здесь
А>Мне нужно, что если метод MethodSynchronized() уже выполнятеся ОДИМ потоком, он не мог выполняться в других.
Тут сама постановка задачи неправильная — недавно в форуме уже где-то это было ...
Блокироваться должны не МЕТОДЫ, а ОБЪЕКТЫ.
Если ты переформулируешь задачу в таком виде,
тогда и решение отыщется просто.
В противном случае еще долго будет продожаться эта бодяга
events vs. locks
А>Мне нужно, что если метод MethodSynchronized() уже выполнятеся ОДИМ потоком, он не мог выполняться в других. А>НО ПРИ ЭТОМ, "другие" методы, пытающиеся выхвать MethodSynchronized из других потоков, просто дождались выполнения MethodSynchronized() А>И НЕ ЗАПУСКАЛИ его, т.е. просто сделали return.
Чё-то очень сложно. Как это "другие" методы будут вызывать, но не дожидаться, да ещё и делать return? Это что, менять выполняемый код на лету?
Re[11]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
15.03.08 09:30
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Тут сама постановка задачи неправильная — недавно в форуме уже где-то это было ...
А>Блокироваться должны не МЕТОДЫ, а ОБЪЕКТЫ.
Ну если уж на то пошло, то что в твоем понимании "блокировка объектов" ?
Правильней тогда уже сказать блокировка одновременного доступа к объектам, путем того-то и того-то
А>Если ты переформулируешь задачу в таком виде, А>тогда и решение отыщется просто. А>В противном случае еще долго будет продожаться эта бодяга А>events vs. locks
Зачем vs? Это разные вещи. И испольщовать их можно по-разному.
Re[11]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
15.03.08 09:35
Оценка:
Здравствуйте, mihailik, Вы писали:
M>Чё-то очень сложно. Как это "другие" методы будут вызывать, но не дожидаться, да ещё и делать return? Это что, менять выполняемый код на лету?
Никаких изменений кода налету.
Я же пример привел примерный:
private readonly object _syncFunction = new object();
private bool _syncFunctionBusy = false;
private ManualResetEvent methodDone = new ManualResetEvent(false);
private object MethodSynchronized()
{
lock(_syncFunction)
{
if(_syncFunctionBusy)
{
methodDone.Reset();
return null;
}
_syncFunctionBusy = true;
}
try
{
//...
//...return new object();
}
finally
{
lock(_syncFunction)
{
_syncFunctionBusy = false;
methodDone.Set();
}
}
}
private void CallSynchronized()//это пример одного из методов, которые не должнны вызывать
//MethodSynchronized() одновременно из нескольких потоков
{
if( MethodSynchronized() == null )//уже выполняется?
{
methodDone.WaitOne();//просто ожидаем его завершения
}
}
M>>Чё-то очень сложно. Как это "другие" методы будут вызывать, но не дожидаться, да ещё и делать return? Это что, менять выполняемый код на лету?
А>Никаких изменений кода налету. А>Я же пример привел примерный:
Это чего, вместо простого lock(...) писать 60 строчек кода? Лихо.
А зачем?
Re[13]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
16.03.08 11:16
Оценка:
Здравствуйте, mihailik, Вы писали:
M>Это чего, вместо простого lock(...) писать 60 строчек кода? Лихо.
Я был бы тебе признатален, если бы ты показал, как "правильно"
написать вод для описанного поведения.
Здравствуйте, <Аноним>, Вы писали:
M>>И плюс lock в тысячу раз дешевле Manual/AutoResetEvent.
А>Я это понимаю.
А>Мне не нужно чтобы метод ПРОСТО не мог выполняться одновременно из нескольких потоков c одним НО (см. ниже).
А>Допустим есть метод MethodSynchorinzed(), который может вызываться кучей "других" методов. А>Каждый из этих "других" методов может вызываться в отдельном потоке.
А>Мне нужно, что если метод MethodSynchronized() уже выполнятеся ОДИМ потоком, он не мог выполняться в других. А>НО ПРИ ЭТОМ, "другие" методы, пытающиеся выхвать MethodSynchronized из других потоков, просто дождались выполнения MethodSynchronized() А>И НЕ ЗАПУСКАЛИ его, т.е. просто сделали return.
непонятно зачем вы изобретаете велосипед? для достижения поставленной цели достаточно всеголишь поместить код метода MethodSynchronized в секцию lock и всё.
Здравствуйте, <Аноним>, Вы писали:
M>>Это чего, вместо простого lock(...) писать 60 строчек кода? Лихо.
А>Я был бы тебе признатален, если бы ты показал, как "правильно" А>написать вод для описанного поведения.
вот так:
private readonly object _syncFunction = new object();
private object MethodSynchronized()
{
lock(_syncFunction) //уже выполняется? тогда просто ожидаем его завершения
{
//...
//...return new object();
}
}
private void CallSynchronized()//это пример одного из методов, которые не должнны вызывать MethodSynchronized() одновременно из нескольких потоков
{
MethodSynchronized()
}
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[15]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
17.03.08 11:34
Оценка:
Здравствуйте, _Morpheus_, Вы писали:
_M_>Здравствуйте, <Аноним>, Вы писали:
M>>>Это чего, вместо простого lock(...) писать 60 строчек кода? Лихо.
А>>Я был бы тебе признатален, если бы ты показал, как "правильно" А>>написать вод для описанного поведения.
_M_>вот так: _M_>
_M_>private readonly object _syncFunction = new object();
_M_>private object MethodSynchronized()
_M_>{
_M_> lock(_syncFunction) //уже выполняется? тогда просто ожидаем его завершения
_M_> {
_M_> //...
_M_> //...
_M_> return new object();
_M_> }
_M_>}
_M_>private void CallSynchronized()//это пример одного из методов, которые не должнны вызывать MethodSynchronized() одновременно из нескольких потоков
_M_>{
_M_> MethodSynchronized()
_M_>}
_M_>
Мда... Или я совсем уж костноязычный и не могу доходчиво объяснить.. Либо..
В таком варианте если CallSynchronized будет одновременно вызван, скажем, из 2-ух потоков, то первый из них получит lock и БУДЕТ ВЫПОЛНЯТЬСЯ, воторой в это время будет ждать пока первый не закончит выолныние и не сделает Monitor.Exit. В этот момент 2-ой поток НАЧНЕТ ВЫОЛНЕНИЕ кода MethodSynchronized!! А мне это не надо
Сколько раз можено повторять — если метод будет вызван одновременно, поток, который пришел (в данном случае) вторым должен ПРОСТО ДОЖДАТЬСЯ КОНЦА ВЫОЛНЕНИЯ ЭТОГО МЕТОДА первым потоком и затем завершиться. ВСЕ!
Re[2]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
17.03.08 12:07
Оценка:
Здравствуйте, eugen1001, Вы писали:
E>Здравствуйте, <Аноним>, Вы писали:
The thread that currently owns the lock on the specified object invokes this method in order to release the object so that another thread can access it.
Т.е. вызывая Monitor.Wait, я снимаю лок => последующий вызов Monitor.TryEnter его-таки получит. А ведь в это время код метода (внутри Monitor.TryEnter) уже может исполняться другим потоком.. А мне, как я уже говорил, такое поведени допустить нельзя.
Здравствуйте, <Аноним>, Вы писали:
А>Да, это было бы красиво если бы не одно но..
А>MSDN о Monitor.Wait(): А>
А>The thread that currently owns the lock on the specified object invokes this method in order to release the object so that another thread can access it.
А>
А>Т.е. вызывая Monitor.Wait, я снимаю лок => последующий вызов Monitor.TryEnter его-таки получит. А ведь в это время код метода (внутри Monitor.TryEnter) уже может исполняться другим потоком.. А мне, как я уже говорил, такое поведени допустить нельзя.
Посмотрите внимательно код: если поток вызвал этот метод, то не он является владельцем блокировки.
Здравствуйте, mihailik, Вы писали:
А>>Я был бы тебе признатален, если бы ты показал, как "правильно"
M>Ну, как "правильно" ты уже совершенно корректно показал. А вот как правильно.
M>
В твоем примере, все вызовы CallTheBloodyMethod, которые будут после того как первый из них получит lock, будут ждать пока не произойдет Monitor.Exit(sync). После этого метод NeverCallMeWhileIAmRunning БУДЕТ ВЫЗВАН.
Это противоречит описанному мной требуемому поведению. Неужели я так непонятно свои мысли выражаю?
Здравствуйте, eugen1001, Вы писали:
E>Посмотрите внимательно код: если поток вызвал этот метод, то не он является владельцем блокировки.
Именно. Посему по логике он должен вызывать SynchronizationLockException.
Здравствуйте, Аноним, Вы писали:
А>Мне не нужно чтобы метод ПРОСТО не мог выполняться одновременно из нескольких потоков c одним НО (см. ниже).
А>Допустим есть метод MethodSynchorinzed(), который может вызываться кучей "других" методов. А>Каждый из этих "других" методов может вызываться в отдельном потоке.
А>Мне нужно, что если метод MethodSynchronized() уже выполнятеся ОДИМ потоком, он не мог выполняться в других. А>НО ПРИ ЭТОМ, "другие" методы, пытающиеся выхвать MethodSynchronized из других потоков, просто дождались выполнения MethodSynchronized() А>И НЕ ЗАПУСКАЛИ его, т.е. просто сделали return.
А>Т.е. что-то типа этого: А>
class Program
{
private static void Main()
{
for( int i = 0; i < 200; i++ )
{
new Thread(MethodSynchronized).Start();
}
}
private static int invocationCount = 0;
private static readonly ManualResetEvent jobDone = new ManualResetEvent(false);
private static void MethodSynchronized()
{
if( Interlocked.CompareExchange(ref invocationCount, 1, 0) == 0 )
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " acquired the lock");
try
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " is doing some processing...");
Thread.Sleep(100);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " finished processing...");
}
finally
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " releasing waiting threads...");
jobDone.Set();
Interlocked.Exchange(ref invocationCount, 0);
}
}
else
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " is waiting...");
Thread.Sleep(0);
jobDone.Reset();
jobDone.WaitOne();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " finished waiting. returns.");
}
}
}
Do not fake yourself ;) ICQ#: 198114726
Re[12]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
17.03.08 14:30
Оценка:
Здравствуйте, Dr_Sh0ck, Вы писали:
D_S>>Можно например вот так:
Да, но в этом-то по сути мой изначальный вопрос и был (см. первый пост) — не получится ли так, что некоторые потокb не успеют "освободиться" при ManualResetEvent.Set перед тем как будет сделан ManualResetEvet.Reset?
Ведь может получится так, что Reset будет вызван сразу же после выполнения Set (после ThreadSleep(0))..