Re[12]: Полная копия multicast delegate... как?
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.08.07 09:48
Оценка: 15 (1) +1
Здравствуйте, _FRED_, Вы писали:

_FR>cо структурой таких проблем нет — невозможно получить две ссылки на одну и ту же структуру :о))


А представь, что структура является полем объекта или элементом массива, к которому идет доступ из разных потоков.
Re[11]: Полная копия multicast delegate... как?
От: romangr Россия  
Дата: 30.08.07 09:49
Оценка: 78 (1)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, nikov, Вы писали:


N>>

N>>When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field. In order to be thread-safe, the addition or removal operations are done while holding the lock (§8.12) on the containing object for an instance event, or the type object (§7.5.10.6) for a static event.

S>Прекольно. То есть они напрашиваются на дедлок? Что ж это они блокируются на объемлющем объекте. И как, кстати, они собрались блокироваться на структуре?

А никак — в ECMA-334 в пункте 17.7.1 Field-like events есть такое примечание:

[Note: Access to a field-like event contained within a struct type is not thread-safe. end note]


А так да — для field-like events сгенерированные компилятором аксессоры add_XXX и remove_XXX
помечаются атрибутом [MethodImpl(MethodImplOptions.Synchronized)]

Specifies that the method can be executed by only one thread at a time. Static methods lock on the type, while instance methods lock on the instance. Only one thread can execute in any of the instance functions and only one thread can execute in any of a class's static functions.

... << RSDN@Home 1.2.0 alpha rev. 717>>
Re[13]: Полная копия multicast delegate... как?
От: _FRED_ Черногория
Дата: 30.08.07 10:18
Оценка: 21 (1)
Здравствуйте, nikov, Вы писали:

_FR>>cо структурой таких проблем нет — невозможно получить две ссылки на одну и ту же структуру :о))


N>А представь, что структура является полем объекта или элементом массива, к которому идет доступ из разных потоков.



namespace ConsoleApplication1
{
  using System;
  using System.Diagnostics;

  internal class Program
  {
    private struct Test
    {
      public event EventHandler Event;

      public void Raise()
      {
        if(Event != null)
        {
          Event(this, EventArgs.Empty);
        }//if
      }
    }

    private readonly Test test;

    static void Main(string[] args)
    {
      Program p = new Program();
      p.test.Event += delegate { Debug.Print("Test 1"); };
      p.test.Event += delegate { Debug.Print("Test 2"); };
      p.test.Raise();

      Test[] tests = new Test[1];
      tests[0].Event += delegate { Debug.Print("Test 3"); };
      tests[0].Event += delegate { Debug.Print("Test 4"); };
      tests[0].Raise();
    }
  }
}


Сработает только вариант с массивом (третий и четвёртый тесты). Спасибо, не подумал.
В первом же случае (поле объекта) ни один Print не вызовется.
Help will always be given at Hogwarts to those who ask for it.
Re[7]: Полная копия multicast delegate... как?
От: xpg934 Россия www.siisltd.ru
Дата: 30.08.07 10:29
Оценка:
N>Поле-то ссылочного типа, а значит, операции чтения-записи являются атомарными.

N>Ecma-334, 12.5 Atomicity of variable references

N>

N>Reads and writes of the following data types shall be atomic: bool, char, byte, sbyte, short, ushort,
N>uint, int, float, and reference types.


N>Другое дело, что при некоторых моделях памяти, изменение, сделанное в одном потоке, может быть не сразу видно в другом. Но речь может идти только о запаздывании, а не о нарушении целостности. В этом случае барьер, создаваемый явной блокировкой, может сыграть роль.


да, спасибо. запаздывание не критично, главное чтобы прочитанное значение ссылки было валидным.
Re[5]: Полная копия multicast delegate... как?
От: _uncle  
Дата: 30.08.07 10:33
Оценка: :)
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, _uncle, Вы писали:


_>>а чем не устраивает

_FR>
_>>lock(m_lockObject)
_>>{
_>>   Delegate[] invokations = m_ReceivedRequestHandler.GetInvokationList();
_>>}
_>>...
_FR>


_FR>Разве что тем, что lock в приведённом примере не нужен


lock нужен затем, что пока он готовит мне список invokations кто-то другой подпишется и он вылетит с ошибкой итерации как минимум а скорее всего изза ошибки синхронизации
Re[6]: Полная копия multicast delegate... как?
От: Lloyd Россия  
Дата: 30.08.07 10:37
Оценка:
Здравствуйте, _uncle, Вы писали:

_FR>>Разве что тем, что lock в приведённом примере не нужен


_>lock нужен затем, что пока он готовит мне список invokations кто-то другой подпишется и он вылетит с ошибкой итерации как минимум а скорее всего изза ошибки синхронизации


Делегат — объект немодифицируемый. Где может вылететь-то?
Re[14]: Полная копия multicast delegate... как?
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.08.07 10:38
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>В первом же случае (поле объекта) ни один Print не вызовется.


Кажется, ты нашел ошибку в компиляторе.
Обычно при попытке менять свойство свойства (если первое свойство имеет значимый тип), выдается ошибка на этапе компиляции. Потому что иначе изменения все равно не отобразятся в исходном объекте, а программист может быть введен в заблуждение. А с событиями, оказывается, такое прокатывает. Надо будет внимательнее посмотреть, является ли это пробелом в спецификации, или просто ошибка в реализации компилятора.
Re[12]: Полная копия multicast delegate... как?
От: xpg934 Россия www.siisltd.ru
Дата: 30.08.07 10:38
Оценка:
R>А так да — для field-like events сгенерированные компилятором аксессоры add_XXX и remove_XXX
R>помечаются атрибутом [MethodImpl(MethodImplOptions.Synchronized)]

R>

R>Specifies that the method can be executed by only one thread at a time. Static methods lock on the type, while instance methods lock on the instance. Only one thread can execute in any of the instance functions and only one thread can execute in any of a class's static functions.


это всё касается только C# 3.0? т.е. в 2.0 надо ручками блокировки таки делать?
Re[6]: Полная копия multicast delegate... как?
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.08.07 10:39
Оценка: +1 :))
Здравствуйте, _uncle, Вы писали:

_> и он вылетит с ошибкой итерации как минимум а скорее всего изза ошибки синхронизации


Сильно сказано! Видимо, мы должны это записать?
Re[6]: Полная копия multicast delegate... как?
От: xpg934 Россия www.siisltd.ru
Дата: 30.08.07 10:41
Оценка:
_>>>а чем не устраивает
_FR>>
_>>>lock(m_lockObject)
_>>>{
_>>>   Delegate[] invokations = m_ReceivedRequestHandler.GetInvokationList();
_>>>}
_>>>...
_FR>>


_FR>>Разве что тем, что lock в приведённом примере не нужен


_>lock нужен затем, что пока он готовит мне список invokations кто-то другой подпишется и он вылетит с ошибкой итерации как минимум а скорее всего изза ошибки синхронизации


не, так не будет. Когда кто-то захочет подписаться, будет создан новый делегат, а старый останется нетронутым.
Re[13]: Полная копия multicast delegate... как?
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.08.07 10:41
Оценка:
Здравствуйте, xpg934, Вы писали:

X>это всё касается только C# 3.0? т.е. в 2.0 надо ручками блокировки таки делать?


Нет-нет, это все было так еще с версии 1.0. Просто я заглянул в тот документ, который у меня под рукой.
Re[14]: Полная копия multicast delegate... как?
От: xpg934 Россия www.siisltd.ru
Дата: 30.08.07 10:44
Оценка:
X>>это всё касается только C# 3.0? т.е. в 2.0 надо ручками блокировки таки делать?

N>Нет-нет, это все было так еще с версии 1.0. Просто я заглянул в тот документ, который у меня под рукой.


хм, это многое упрощает. Вопрос не по теме: как посмотреть, помечены ни методы правильным атрибутом? ildasm что-то не показывает...

.event WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate ReceivedRequest
{
  .addon instance void WLPTPCommunications.WLPTPServerTransport::add_ReceivedRequest(class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate)
  .removeon instance void WLPTPCommunications.WLPTPServerTransport::remove_ReceivedRequest(class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate)
} // end of event WLPTPServerTransport::ReceivedRequest
Re[7]: Полная копия multicast delegate... как?
От: _uncle  
Дата: 30.08.07 10:47
Оценка:
Здравствуйте, xpg934, Вы писали:

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


То есть каждый раз при m_ReceivedRequestHandler += value меняется instance m_ReceivedRequestHandler ? надо проверить... не знаю, может она еще и атомарная ?
Re[8]: Полная копия multicast delegate... как?
От: Lloyd Россия  
Дата: 30.08.07 10:50
Оценка:
Здравствуйте, _uncle, Вы писали:

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


_>То есть каждый раз при m_ReceivedRequestHandler += value меняется instance m_ReceivedRequestHandler ? надо проверить... не знаю, может она еще и атомарная ?


Нет, instance, на который указывает m_ReceivedRequestHandler, не меняется. Меняется значение поля m_ReceivedRequestHandler (ему присваивается созданный делегат).
Re[8]: Полная копия multicast delegate... как?
От: xpg934 Россия www.siisltd.ru
Дата: 30.08.07 10:50
Оценка:
X>>не, так не будет. Когда кто-то захочет подписаться, будет создан новый делегат, а старый останется нетронутым.

_>То есть каждый раз при m_ReceivedRequestHandler += value меняется instance m_ReceivedRequestHandler ?

точно так. Т.к. однажды созданный делегат никогда больше не меняется.

_>надо проверить... не знаю, может она еще и атомарная ?

не, но вот как раз копаю чтобы убедиться, что += и -= по умолчанию thread-safe
Re[15]: Полная копия multicast delegate... как?
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.08.07 10:52
Оценка:
Здравствуйте, xpg934, Вы писали:

X>хм, это многое упрощает. Вопрос не по теме: как посмотреть, помечены ни методы правильным атрибутом? ildasm что-то не показывает...


X>
X>.event WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate ReceivedRequest
X>{
X>  .addon instance void WLPTPCommunications.WLPTPServerTransport::add_ReceivedRequest(class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate)
X>  .removeon instance void WLPTPCommunications.WLPTPServerTransport::remove_ReceivedRequest(class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate)
X>} // end of event WLPTPServerTransport::ReceivedRequest
X>


А надо смотреть не event, а сами методы-аксессоры.
Кроме того, это хитрый атрибут, он будет показан с помощью слова synchronized после сигнатуры.
Re[16]: Полная копия multicast delegate... как?
От: xpg934 Россия www.siisltd.ru
Дата: 30.08.07 10:55
Оценка:
X>>хм, это многое упрощает. Вопрос не по теме: как посмотреть, помечены ни методы правильным атрибутом? ildasm что-то не показывает...

X>>
X>>.event WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate ReceivedRequest
X>>{
X>>  .addon instance void WLPTPCommunications.WLPTPServerTransport::add_ReceivedRequest(class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate)
X>>  .removeon instance void WLPTPCommunications.WLPTPServerTransport::remove_ReceivedRequest(class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate)
X>>} // end of event WLPTPServerTransport::ReceivedRequest
X>>


N>А надо смотреть не event, а сами методы-аксессоры.

N>Кроме того, это хитрый атрибут, он будет показан с помощью слова synchronized после сигнатуры.

смотрю... и ничего похожего на synchronized:


.method public hidebysig specialname instance void 
        add_ReceivedRequest(class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate 'value') cil managed
{
  // Code size       50 (0x32)
  .maxstack  3
  .locals init ([0] object CS$2$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldfld      object WLPTPCommunications.WLPTPServerTransport::m_HandlersLock
  IL_0007:  dup
  IL_0008:  stloc.0
  IL_0009:  call       void [mscorlib]System.Threading.Monitor::Enter(object)
  IL_000e:  nop
  .try
  {
    IL_000f:  ldarg.0
    IL_0010:  dup
    IL_0011:  ldfld      class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate WLPTPCommunications.WLPTPServerTransport::m_ReceivedRequestHandler
    IL_0016:  ldarg.1
    IL_0017:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
                                                                                            class [mscorlib]System.Delegate)
    IL_001c:  castclass  WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate
    IL_0021:  stfld      class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate WLPTPCommunications.WLPTPServerTransport::m_ReceivedRequestHandler
    IL_0026:  leave.s    IL_0030
  }  // end .try
  finally
  {
    IL_0028:  ldloc.0
    IL_0029:  call       void [mscorlib]System.Threading.Monitor::Exit(object)
    IL_002e:  nop
    IL_002f:  endfinally
  }  // end handler
  IL_0030:  nop
  IL_0031:  ret
} // end of method WLPTPServerTransport::add_ReceivedRequest
Re[17]: Полная копия multicast delegate... как?
От: romangr Россия  
Дата: 30.08.07 10:58
Оценка:
Здравствуйте, xpg934, Вы писали:

[skip]

X>смотрю... и ничего похожего на synchronized:



X>
X>.method public hidebysig specialname instance void 
X>        add_ReceivedRequest(class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate 'value') cil managed
X>{
X>  // Code size       50 (0x32)
X>  .maxstack  3
X>  .locals init ([0] object CS$2$0000)
X>  IL_0000:  nop
X>  IL_0001:  ldarg.0
X>  IL_0002:  ldfld      object WLPTPCommunications.WLPTPServerTransport::m_HandlersLock
X>  IL_0007:  dup
X>  IL_0008:  stloc.0
X>  IL_0009:  call       void [mscorlib]System.Threading.Monitor::Enter(object)
X>  IL_000e:  nop
X>  .try
X>  {
X>    IL_000f:  ldarg.0
X>    IL_0010:  dup
X>    IL_0011:  ldfld      class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate WLPTPCommunications.WLPTPServerTransport::m_ReceivedRequestHandler
X>    IL_0016:  ldarg.1
X>    IL_0017:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
X>                                                                                            class [mscorlib]System.Delegate)
X>    IL_001c:  castclass  WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate
X>    IL_0021:  stfld      class WLPTPCommunications.WLPTPServerTransportReceivedRequestDelegate WLPTPCommunications.WLPTPServerTransport::m_ReceivedRequestHandler
X>    IL_0026:  leave.s    IL_0030
X>  }  // end .try
X>  finally
X>  {
X>    IL_0028:  ldloc.0
X>    IL_0029:  call       void [mscorlib]System.Threading.Monitor::Exit(object)
X>    IL_002e:  nop
X>    IL_002f:  endfinally
X>  }  // end handler
X>  IL_0030:  nop
X>  IL_0031:  ret
X>} // end of method WLPTPServerTransport::add_ReceivedRequest

X>


Если ты сам написал аксессоры add_XXX и remove_XXX, то компилятор их ничем помечать не будет
... << RSDN@Home 1.2.0 alpha rev. 717>>
Re[17]: Полная копия multicast delegate... как?
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.08.07 11:01
Оценка:
Здравствуйте, xpg934, Вы писали:

X>смотрю... и ничего похожего на synchronized:


synchronized добавляется только для автоматически созданных аксессоров у field-like event. Если add/remove пишется вручную, то о синхронизации надо заботиться самому.
Re[18]: Полная копия multicast delegate... как?
От: _FRED_ Черногория
Дата: 30.08.07 11:07
Оценка:
Здравствуйте, nikov, Вы писали:

N>Если add/remove пишется вручную, то о синхронизации надо заботиться самому.


Обычно наоборот: если надо самому позаботиться о синхронизации, то надо самому написать add\remove
Help will always be given at Hogwarts to those who ask for it.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.