При использовании анонимных delegate
s в C # CLR сгенерирует копию локальной (например, переменные в текущей области) в куче для используемых переменных.Такой локальный объект будет помещен в кучу для каждой объявленной переменной текущей области.
Вы можете увидеть это поведение в этом примере:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
ThreadPool.QueueUserWorkItem(delegate { execute(i); });
Thread.Sleep(1000);
Console.WriteLine();
for (int i = 0; i < 5; i++)
{
int j = i;
ThreadPool.QueueUserWorkItem(delegate { execute(j); });
}
Thread.Sleep(1000);
}
static void execute(int number)
{
Console.WriteLine(" * NUM=" + number.ToString());
}
}
Вывод этой программы (В последних 5 записях порядок может отличаться, в то время как для первой также можно получить числа меньше 5.):
* NUM=5
* NUM=5
* NUM=5
* NUM=5
* NUM=5
* NUM=0
* NUM=1
* NUM=2
* NUM=3
* NUM=4
C # всегда должен генерировать новую локальную копию при вызове в методе.Это работает, как предполагалось в этом примере:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
call(i);
Thread.Sleep(1000);
}
static void call(int number)
{
ThreadPool.QueueUserWorkItem(delegate { execute(number); });
}
static void execute(int number)
{
Console.WriteLine(" * NUM=" + number.ToString());
}
}
Вывод:
* NUM=0
* NUM=1
* NUM=2
* NUM=3
* NUM=4
Это рассматриваемый случай: Однако, это не работает при присвоении переменной зарезервированной области stackalloc
:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
call(i);
Thread.Sleep(1000);
}
static unsafe void call(int number)
{
int* ints = stackalloc int[64];
ints[32] = number;
ThreadPool.QueueUserWorkItem(delegate { execute(ints[32]); });
}
static void execute(int number)
{
Console.WriteLine(" * NUM=" + number.ToString());
}
}
Вывод:
* NUM=4
* NUM=4
* NUM=4
* NUM=4
* NUM=4
При использовании обычной локальной переменной - просто замените метод call
например выше:
static void call(int number)
{
int j = number;
ThreadPool.QueueUserWorkItem(delegate { execute(j); });
}
Вывод:
* NUM=0
* NUM=1
* NUM=2
* NUM=3
* NUM=4
Эта ситуация заставляет меня не доверять анонимным delegate
s в C # - потому что я не понимаю, когда именно C # не будетиспорти мои звонки анонимным delegate
с.
Мои вопросы: Почему C # не отслеживает пространство stackalloc
относительно анонимных delegate
с? Я знаю оC # не отслеживает.Я хочу знать , почему не отслеживает, если это происходит с обычной переменной.
Я использовал .NET Core 2.1 с C # 7.3, включая переключатель /unsafe
для этих примеров.