Ответ 1
Что касается вызова делегата, то да.
Вызов делегата является потокобезопасным, потому что делегаты являются неизменными. Однако вы должны убедиться, что делегат существует первым. Эта проверка может потребовать некоторых механизмов синхронизации в зависимости от требуемого уровня безопасности.
Например, следующее может вызывать NullReferenceException
, если SomeDelegate
были установлены в нуль другим потоком между нулевой проверкой и вызовом.
if (SomeDelegate != null)
{
SomeDelegate();
}
Ниже приведено несколько более безопасное. Здесь мы используем тот факт, что делегаты неизменны. Даже если другой поток изменяет SomeDelegate
, код не может предотвратить этот pesky NullReferenceException
.
Action local = SomeDelegate;
if (local != null)
{
local();
}
Однако это может привести к тому, что делегат никогда не будет выполнен, если SomeDelegate
было присвоено ненулевое значение в другом потоке. Это связано с проблемой тонкой проблемы с памятью. Ниже приведен самый безопасный метод.
Action local = Interlocked.CompareExchange(ref SomeDelegate, null, null);
if (local != null)
{
local();
}
Что касается выполнения метода, на который ссылается делегат, то ответ отсутствует.
Вам необходимо будет предоставить свои собственные гарантии безопасности потоков с помощью механизмов синхронизации. Это связано с тем, что CLR автоматически не предоставляет гарантию безопасности потока для выполнения делегатов. Возможно, этот метод не требует никакой дополнительной синхронизации для обеспечения безопасности, особенно если он никогда не получает доступ к общему состоянию. Однако, если метод читает или записывает из общей переменной, вам придется подумать о том, как защитить от одновременного доступа из нескольких потоков.