Здравствуйте, <Аноним>, Вы писали:
_M_>>не проще ли AutoResetEvent использовать? Зачем гробить память и процессорное время, только для того чтобы сбрасывать событие?
А>Мне по Set надо освобождать не 1 поток, а все потоки которые могут ждать на этом ивенте.
специально для таких случаев предназначены методы Monitor.Pulse() и Monitor.PulseAll(), тебе в данном случае нужен Monitor.PulseAll()
Здравствуйте, <Аноним>, Вы писали:
_M_>>ничего лочиться не должно, причем нужно чтобы лочилось? это как?
А>Это так, как я описал — ожидающие завершщения функцции потоки ждут не в операторе lock, а на ManualresetEvent.WaitOne.
lock и WaitOne() это одно и тоже — и то и другое отдает процессорное время системе для других потоков...
_M_>>То что вы описали — чистейшая функциональность lock'а
А>Частично (в функции) — да. Но повотрю еще раз — если функция выполняется одним потоком, и в это время вызвана другим потоком, он должен просто дождаться ее завершения. И ВСЕ. Из ждущего потока функция вызвываться не должна.
из ждущего потока функция вызываться не может по определению, т.к. ждущий поток спит — у него нет процессорного времени чтобы вызвать функцию...
А>Частично это так и сделано. Только, как я уже говорил, если функция будет вызвана из другого потока во время ее выполения, этот поток не просто дложен получить null и успокоиться, а ждать на ManualResetEvent, который будет выставлен в Set cамой функцией по окончании своей работы.
тогда вам такой подход не нужен, вам нужен обычный lock, без всяких возвратов null
А>Вы мне сказали, что это нужно делать при помощи Monitor.PulseAll, только вот его я здесь и не вижу
да точно также как с событием, только вместо вызова Set, вызывать нужно PulseAll — это аналог Set, Reset, но с той разницей что проснутся все потоки ожидающие освобождения заданного объекта
Здравствуйте, eugen1001, Вы писали:
E>Посмотрите внимательно код: если поток вызвал этот метод, то не он является владельцем блокировки.
Именно. Посему по логике он должен вызывать SynchronizationLockException.
Неа. Тот код ждет пока не завершится выполнение метода в другом потоке и потом выходит
Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
12.03.08 15:32
Оценка:
Есть объект ManualResetEvent.
В одном ("первом") потоке при одних условиях ему может делаться Set, а в другом ("втором") потоке — Reset.
Вопрос в следующем. Надо ли синхронизировать доступ к ManualResetEvent при доступе к нему из разных потоков?
Ведь возможна следующая ситуация. Пусть N каких-то "других" потоков ждут на этом ивенте (ManualresetEvent.WaitOne).
Пусть "первый" поток делает ManualResetEvent.Set чтобы "отпустить" все N ждущих потоков.
А в следующий квант процессорного времени "второй" поток делает этуму же ивенту ManualResetEvent.Reset.
Не получится ли так, что действие "второго" потока полностью или частично "отменит" действие "первого", т.е. не все N ждущих потоков будут освобожденны (или вообще ни один из них) когда "первый" поток вызвал Set?
Здравствуйте, <Аноним>, Вы писали:
А>Не получится ли так, что действие "второго" потока полностью или частично "отменит" действие "первого", т.е. не все N ждущих потоков будут освобожденны (или вообще ни один из них) когда "первый" поток вызвал Set?
Может.
... << RSDN@Home 1.2.0 alpha rev. 789>>
Re[2]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
12.03.08 16:33
Оценка:
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, <Аноним>, Вы писали:
А>>Не получится ли так, что действие "второго" потока полностью или частично "отменит" действие "первого", т.е. не все N ждущих потоков будут освобожденны (или вообще ни один из них) когда "первый" поток вызвал Set? GZ>Может.
Хм.. Т.е. действия Set/Reset выведение "ждущих" потоков из ждущего состояния (WaitOne) операции не атомарные?
Здравствуйте, <Аноним>, Вы писали:
А>Здравствуйте, GlebZ, Вы писали:
GZ>>Здравствуйте, <Аноним>, Вы писали:
А>>>Не получится ли так, что действие "второго" потока полностью или частично "отменит" действие "первого", т.е. не все N ждущих потоков будут освобожденны (или вообще ни один из них) когда "первый" поток вызвал Set? GZ>>Может.
А>Хм.. Т.е. действия Set/Reset выведение "ждущих" потоков из ждущего состояния (WaitOne) операции не атомарные?
Нет. В той ситуации которой ты описал возможно что некоторые треды не успеют зарелизиться. Освобождение только одного потока гарантировано. Если у тебя не тысячи тредов, то достаточно перед резетом вставить Thread.Sleep(0) чтобы передать управление.
... << RSDN@Home 1.2.0 alpha rev. 789>>
Re[4]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
12.03.08 17:03
Оценка:
Здравствуйте, GlebZ, Вы писали:
А>>Хм.. Т.е. действия Set/Reset выведение "ждущих" потоков из ждущего состояния (WaitOne) операции не атомарные?
GZ>Нет. В той ситуации которой ты описал возможно что некоторые треды не успеют зарелизиться. Освобождение только одного потока гарантировано. Если у тебя не тысячи тредов, то достаточно перед резетом вставить Thread.Sleep(0) чтобы передать управление.
Здравствуйте, <Аноним>, Вы писали:
А>Ведь возможна следующая ситуация. Пусть N каких-то "других" потоков ждут на этом ивенте (ManualresetEvent.WaitOne). А>Пусть "первый" поток делает ManualResetEvent.Set чтобы "отпустить" все N ждущих потоков. А>А в следующий квант процессорного времени "второй" поток делает этуму же ивенту ManualResetEvent.Reset.
не проще ли AutoResetEvent использовать? Зачем гробить память и процессорное время, только для того чтобы сбрасывать событие?
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[2]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
12.03.08 17:32
Оценка:
Здравствуйте, _Morpheus_, Вы писали:
_M_>не проще ли AutoResetEvent использовать? Зачем гробить память и процессорное время, только для того чтобы сбрасывать событие?
Мне по Set надо освобождать не 1 поток, а все потоки которые могут ждать на этом ивенте.
Здравствуйте, <Аноним>, Вы писали:
А>Здравствуйте, GlebZ, Вы писали:
GZ>>Здравствуйте, <Аноним>, Вы писали:
А>>>Не получится ли так, что действие "второго" потока полностью или частично "отменит" действие "первого", т.е. не все N ждущих потоков будут освобожденны (или вообще ни один из них) когда "первый" поток вызвал Set? GZ>>Может.
А>Хм.. Т.е. действия Set/Reset выведение "ждущих" потоков из ждущего состояния (WaitOne) операции не атомарные?
атомарные, но если для потока который должен был проснуться не нашлось кванта времени, и event был сброшен обратно, то поток будет продолжать находиться в ожидании...
Здравствуйте, AndrewVK, Вы писали:
А>>Не получится ли так, что действие "второго" потока полностью или частично "отменит" действие "первого"
AVK>не получится.
получится, например если не нашлось кванта времени для потоков которые должны были проснуться за весь период, пока событие находилось во взведенном состоянии, то потоки так и не проснутся и будут продолжать ожидание...
вот пример, не смотря на то что событие было установлено и сброшено, это не приводит к тому чтобы потоки проснулись, т.к. за время пока событие было взведено у потоков небыло времени чтобы проснуться, а когда время появилось событие было уже сброшено:
using System;
using System.Threading;
public class Program
{
static void Main()
{
Program p = new Program();
p.Run();
}
private ManualResetEvent _event = new ManualResetEvent(false);
private AutoResetEvent _readyThread1 = new AutoResetEvent(false);
private AutoResetEvent _readyThread2 = new AutoResetEvent(false);
public void Run()
{
Thread t1 = new Thread(new ThreadStart(threadProc1));
t1.Name = "Thread1";
t1.IsBackground = true;
Thread t2 = new Thread(new ThreadStart(threadProc2));
t2.Name = "Thread1";
t2.IsBackground = true;
// переводим свой поток в очередь более главных потоков, чтобы время в первую очередь доставалось текущему потоку и в последнюю очередь, когда он добровольно отдаст управление, потокам t1 и t2...
t1.Priority = ThreadPriority.BelowNormal;
t2.Priority = ThreadPriority.BelowNormal;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
t1.Start();
t2.Start();
_readyThread1.WaitOne();
_readyThread2.WaitOne();
Console.WriteLine("Set/Reset...");
_event.Set();
_event.Reset();
// разрешаем делиться временем с потоками t1 и t2...
t1.Priority = ThreadPriority.Normal;
t2.Priority = ThreadPriority.Normal;
Thread.CurrentThread.Priority = ThreadPriority.Normal;
// событие было установлено и сброшено, но потоки не проснутся (если процессу доступно не более 1 процессора!)
Console.WriteLine("Wait for processing...");
Thread.Sleep(5000);
Console.WriteLine("Exit...");
}
private void threadProc1()
{
_readyThread1.Set();
_event.WaitOne();
Console.WriteLine("T1");
}
private void threadProc2()
{
_readyThread2.Set();
_event.WaitOne();
Console.WriteLine("T2");
}
}
если у вас многопроцессорная машина, то нужно прибить процесс только к одному процу...
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[4]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
12.03.08 18:14
Оценка:
Здравствуйте, _Morpheus_, Вы писали:
_M_>специально для таких случаев предназначены методы Monitor.Pulse() и Monitor.PulseAll(), тебе в данном случае нужен Monitor.PulseAll()
Не уверен что ты меня правильно понял.
Есть функция, которая может выполняться из разных потоков. Но одновременно должна — только в одном. Причем, если во время выполнения функции в каком-либо потоке, другой поток попытается ее запустить, ничего "лочится" не должно. Другой поток должен в этом случае просто дожаться выполнения функции в первом потоке. И все.
Вот как это организовано.
Если функция уже выполняется в одном из потоков, то при попытке ее вызова из другого, функция возвращает null.
Код, вызывающий эту функцию, проверяет, а не вернулся ли null. Если да, то он "вешается" на событие и ждет (ManualResetEvent.WaitOne). То что он будет ждать — гарантированно. Т.к. первым делом код функции делает ManualResetEvent.Reset.
Перед возвратом, функция делает ManualResetEvent.Set. Предполагается, что все ждущие потоки при этом выйдут из ожидания. При этом функцию выпонять они уже не будут (см. изначальное условие).
Но я опасаюсь вот чего. Если перед тем, как успеют проснуться все потоки (после ManualresetEvet.Set), функция будет вызвана еще раз (т.е. будет опять сделать ManualResetEvent.Reset), то у них и шанса-то проснуться не будет.
Как мне здеть может помочь Monitor и PulseAll, объясни плз поподробнее..
Здравствуйте, <Аноним>, Вы писали:
А>А если тысячи?..
А если тысячи — то ReaderWriterLock. Все ожидающие как ReaderLock. Основная WriterLock. Там вроде бы гарантируется.
Здравствуйте, <Аноним>, Вы писали:
_M_>>специально для таких случаев предназначены методы Monitor.Pulse() и Monitor.PulseAll(), тебе в данном случае нужен Monitor.PulseAll()
А>Не уверен что ты меня правильно понял.
А>Есть функция, которая может выполняться из разных потоков. Но одновременно должна — только в одном. Причем, если во время выполнения функции в каком-либо потоке, другой поток попытается ее запустить, ничего "лочится" не должно. Другой поток должен в этом случае просто дожаться выполнения функции в первом потоке. И все.
ничего лочиться не должно, причем нужно чтобы лочилось? это как?
То что вы описали — чистейшая функциональность lock'а
А>Вот как это организовано. А>Если функция уже выполняется в одном из потоков, то при попытке ее вызова из другого, функция возвращает null.
А>Но я опасаюсь вот чего. Если перед тем, как успеют проснуться все потоки (после ManualresetEvet.Set), функция будет вызвана еще раз (т.е. будет опять сделать ManualResetEvent.Reset), то у них и шанса-то проснуться не будет.
А>Как мне здеть может помочь Monitor и PulseAll, объясни плз поподробнее..
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[6]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
13.03.08 10:09
Оценка:
Здравствуйте, GlebZ, Вы писали:
GZ>А если тысячи — то ReaderWriterLock. Все ожидающие как ReaderLock. Основная WriterLock. Там вроде бы гарантируется.
Спасибо, попробую разобраться.
Re[6]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
13.03.08 11:55
Оценка:
Здравствуйте, _Morpheus_, Вы писали:
_M_>ничего лочиться не должно, причем нужно чтобы лочилось? это как?
Это так, как я описал — ожидающие завершщения функцции потоки ждут не в операторе lock, а на ManualresetEvent.WaitOne.
_M_>То что вы описали — чистейшая функциональность lock'а
Частично (в функции) — да. Но повотрю еще раз — если функция выполняется одним потоком, и в это время вызвана другим потоком, он должен просто дождаться ее завершения. И ВСЕ. Из ждущего потока функция вызвываться не должна.
_M_>это можно делать так: _M_>
Частично это так и сделано. Только, как я уже говорил, если функция будет вызвана из другого потока во время ее выполения, этот поток не просто дложен получить null и успокоиться, а ждать на ManualResetEvent, который будет выставлен в Set cамой функцией по окончании своей работы.
Вы мне сказали, что это нужно делать при помощи Monitor.PulseAll, только вот его я здесь и не вижу
_M_>тогда вам такой подход не нужен, вам нужен обычный lock, без всяких возвратов null
И плюс lock в тысячу раз дешевле Manual/AutoResetEvent.
Re[9]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
14.03.08 08:48
Оценка:
Здравствуйте, mihailik, Вы писали:
_M_>>тогда вам такой подход не нужен, вам нужен обычный lock, без всяких возвратов null
M>И плюс lock в тысячу раз дешевле Manual/AutoResetEvent.
Я это понимаю.
Мне не нужно чтобы метод ПРОСТО не мог выполняться одновременно из нескольких потоков c одним НО (см. ниже).
Допустим есть метод MethodSynchorinzed(), который может вызываться кучей "других" методов.
Каждый из этих "других" методов может вызываться в отдельном потоке.
Мне нужно, что если метод MethodSynchronized() уже выполнятеся ОДИМ потоком, он не мог выполняться в других.
НО ПРИ ЭТОМ, "другие" методы, пытающиеся выхвать MethodSynchronized из других потоков, просто дождались выполнения MethodSynchronized()
И НЕ ЗАПУСКАЛИ его, т.е. просто сделали return.
Здравствуйте, _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 БУДЕТ ВЫЗВАН.
Это противоречит описанному мной требуемому поведению. Неужели я так непонятно свои мысли выражаю?
Здравствуйте, Аноним, Вы писали:
А>Мне не нужно чтобы метод ПРОСТО не мог выполняться одновременно из нескольких потоков 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))..
Здравствуйте, <Аноним>, Вы писали:
А>Мне нужно, что если метод MethodSynchronized() уже выполнятеся ОДИМ потоком, он не мог выполняться в других. А>НО ПРИ ЭТОМ, "другие" методы, пытающиеся выхвать MethodSynchronized из других потоков, просто дождались выполнения MethodSynchronized() А>И НЕ ЗАПУСКАЛИ его, т.е. просто сделали return.
Здравствуйте, <Аноним>, Вы писали:
А>А вот это уже похоже на то что нужно. И кода совсем немного. А>Надо прикинуть как это влезет в уже существующий код. Спасибо!
Да не за что.
P.S. Для спасибо есть кнопка.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[12]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
18.03.08 09:01
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Lloyd, Вы писали:
L>>Вот так не пойдет? L>>
А>А вот это уже похоже на то что нужно. И кода совсем немного. А>Надо прикинуть как это влезет в уже существующий код. Спасибо!
Что-то вечером вчера я не туда смотрел похоже
Это решение тоже не дает нужного поведения. Ведь когда мы входим в lock, после Monitor.Exit только один поток освободится, а мне надо чтобы освободились все, которые можгут ждать.
В этом варианте, если CallTheBloodyMethod будет вызван из потока в то время, когда он уже выполняется каким-либо другим потоком, этот метод просто завершится, а мне надо чтоб он дождался пока другой поток не закончит его выполнение.
Здравствуйте, <Аноним>, Вы писали:
А>Что-то вечером вчера я не туда смотрел похоже А>Это решение тоже не дает нужного поведения. Ведь когда мы входим в lock, после Monitor.Exit только один поток освободится, а мне надо чтобы освободились все, которые можгут ждать.
Тебе имеет смысл подменять каждый раз объект синхронизации:
т.е. поток выполняющий функцию, создаёт новый объект синхронизации и назначает его в качестве текущего объекта синхронизации. Остальные потоки ожидают освобождения текущего объекта синхронизации.
После того, как функция завершена, поток сбрасывает текущий объект синхронизации в null, а затем освобождает сам объект синхронизации.
Наличие назначенного текущего объекта синхронизации есть признак того, что функция уже выполняется.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, GlebZ, Вы писали:
А>А почему ты говоришь что оно должно зависнуть? А>У меня для 10000 потоков отработало нормально.
Там в коде реально баг, и оно может при определнных условиях зависнуть. Может быть ситуация когда поток который выполняет метод DoSmth вызвал PulseAll, но при этом остались потоки, которые еще не вызвали Wait, так вот эти потоки зависнут когда вызовут Wait (если конечно еще раз не вызвать PulseAll).
Re[7]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
21.03.08 17:07
Оценка:
Здравствуйте, Александр Малафеев, Вы писали:
АМ>Там в коде реально баг, и оно может при определнных условиях зависнуть. Может быть ситуация когда поток который выполняет метод DoSmth вызвал PulseAll, но при этом остались потоки, которые еще не вызвали Wait, так вот эти потоки зависнут когда вызовут Wait (если конечно еще раз не вызвать PulseAll).
Да, теперь вижу.
Тогда опять получается что кроме как с ManualResetEvent это не решить (хотя там тоже, как видно из первого поста не так все гладко).
Где ж 100% солюшн?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Александр Малафеев, Вы писали:
АМ>>Там в коде реально баг, и оно может при определнных условиях зависнуть. Может быть ситуация когда поток который выполняет метод DoSmth вызвал PulseAll, но при этом остались потоки, которые еще не вызвали Wait, так вот эти потоки зависнут когда вызовут Wait (если конечно еще раз не вызвать PulseAll).
А>Да, теперь вижу. А>Тогда опять получается что кроме как с ManualResetEvent это не решить (хотя там тоже, как видно из первого поста не так все гладко). А>Где ж 100% солюшн?
Мой последний вариант без этого бага
Там для этого специально флаг ввел, чтобы не делать Wait если потом не будет Pulse.
Re[9]: Конкурентный доступ к ManulaResetEvent
От:
Аноним
Дата:
21.03.08 18:13
Оценка:
Здравствуйте, Александр Малафеев, Вы писали:
А>>Где ж 100% солюшн?
АМ>Мой последний вариант без этого бага АМ>Там для этого специально флаг ввел, чтобы не делать Wait если потом не будет Pulse.
Так-то оно так, тока выглядит оч уж страшно.. Что обо мне подумают те, кто это мэйнтейнить будет