Перегрузить класс Thread и добавить свойство / событие?
Если под "перегрузкой" вы на самом деле подразумеваете наследовать, то нет.Thread
запечатан, поэтому он не может быть унаследован, что означает, что вы не сможете добавить какие-либо свойства или события к нему.
Еще одно более элегантное решение?
Создайте класс, который инкапсулирует логику, которая будет выполняться потоком.Добавьте свойство или событие (или оба), которые можно использовать для получения информации о прогрессе.
public class Worker
{
private Thread m_Thread = new Thread(Run);
public event EventHandler<ProgressEventArgs> Progress;
public void Start()
{
m_Thread.Start();
}
private void Run()
{
while (true)
{
// Do some work.
OnProgress(new ProgressEventArgs(...));
// Do some work.
}
}
private void OnProgress(ProgressEventArgs args)
{
// Get a copy of the multicast delegate so that we can do the
// null check and invocation safely. This works because delegates are
// immutable. Remember to create a memory barrier so that a fresh read
// of the delegate occurs everytime. This is done via a simple lock below.
EventHandler<ProgressEventArgs> local;
lock (this)
{
var local = Progress;
}
if (local != null)
{
local(this, args);
}
}
}
Обновление:
Позвольте мне быть немного более яснымпочему барьер памяти необходим в этой ситуации.Барьер предотвращает перемещение чтения перед другими инструкциями.Наиболее вероятная оптимизация не от ЦП, а от JIT-компилятора, «поднимающего» чтение Progress
за пределы цикла while
.Это движение создает впечатление «несвежих» чтений.Вот полуреалистичная демонстрация проблемы.
class Program
{
static event EventHandler Progress;
static void Main(string[] args)
{
var thread = new Thread(
() =>
{
var local = GetEvent();
while (local == null)
{
local = GetEvent();
}
});
thread.Start();
Thread.Sleep(1000);
Progress += (s, a) => { Console.WriteLine("Progress"); };
thread.Join();
Console.WriteLine("Stopped");
Console.ReadLine();
}
static EventHandler GetEvent()
{
//Thread.MemoryBarrier();
var local = Progress;
return local;
}
}
Крайне важно, чтобы сборка Release запускалась без процесса vshost.Любой из них отключит оптимизацию, которая обнаруживает ошибку (я думаю, что это не воспроизводится в версиях фреймворка 1.0 и 1.1, а также из-за их более примитивной оптимизации).Ошибка заключается в том, что «Остановлено» никогда не отображается, даже если оно явно должно быть.Теперь раскомментируйте вызов Thread.MemoryBarrier
и обратите внимание на изменение поведения.Также имейте в виду, что даже самые тонкие изменения в структуре этого кода в настоящее время ограничивают способность компилятора выполнять данную оптимизацию.Одним из таких изменений будет фактический вызов делегата.Другими словами, вы не можете в настоящее время воспроизвести проблему устаревшего чтения, используя нулевую проверку, сопровождаемую шаблоном вызова, но в спецификации CLI есть (1029 * ничто ) (о котором я все равно знаю), чтозапрещает будущему гипотетическому JIT-компилятору повторно применять эту «подъемную» оптимизацию.