Где в C # мне хранить ссылку на таймер? - PullRequest
14 голосов
/ 25 января 2009

Документация System.Threading.Timer гласит, что я должен сохранить реальную ссылку на нее, чтобы избежать ее сбора мусора. Но где мне это сделать? Мой main очень прост, поэтому я не знаю, где хранить ссылку:

class Program {
    static void Main() {
        new System.Threading.Thread(myThreadStart).Start();
        new System.Threading.Timer(myTimerCallback, new MyStateObject(), 0, 5000);
    }
}

Я думал о том, чтобы сохранить ссылку в поле static в классе Program, предполагая, что поля static не собираются до конца приложения. Но я не уверен, что это лучший способ сделать это, поэтому буду признателен за ваш совет.

Ответы [ 3 ]

18 голосов
/ 25 января 2009

Если ваш Timer является объектом уровня приложения, нет ничего плохого в том, чтобы сделать его закрытым статическим членом вашего класса Main. В любом случае, я бы так и сделал.

12 голосов
/ 25 января 2009

РЕДАКТИРОВАТЬ: мой оригинальный ответ мусор. На самом деле мусор. Я сохранил это здесь, чтобы объяснить , почему это мусор, хотя - это в комментариях, но они были бы удалены с ответом.

GC.KeepAlive только гарантирует, что ссылка обрабатывается как корень до окончания вызова. В коде внизу этого ответа метод GC.KeepAlive будет вызван немедленно, и тогда таймер все еще будет иметь право на сборку мусора. Поскольку вновь созданный поток является потоком переднего плана, приложение будет работать, пока оно живо (в то время как таймер использует фоновый поток, который не предотвращает выход из программы). Это означает, что метод Main завершается, но приложение должно продолжать работать.

Возможно, более простым решением было бы запустить myThreadStart в главном потоке, а не создавать новый, а затем позволить основному потоку умереть. Другими словами, простое решение будет:

using System.Threading;

class Program {
    static void Main() {
        Timer timer = new Timer(myTimerCallback, 
                                new MyStateObject(), 0, 5000);
        myThreadStart();
        GC.KeepAlive(timer);
    }
}

Я предполагаю, что код real более сложен - в этом случае использование приватной статической переменной, как предложено в других ответах, вероятно, путь. Это действительно будет зависеть от использования, хотя. Лично я предпочитаю не создавать статическое поле только для предотвращения сбора чего-либо, если есть альтернатива (как указано выше), но иногда это практически единственный способ сделать это.

Оригинальный (плохой) ответ:

Если вы действительно хотите разместить его в Main, вы можете использовать GC.KeepAlive :

using System.Threading;

class Program {
    static void Main() {
        new Thread(myThreadStart).Start();
        Timer timer = new Timer(myTimerCallback, 
                                new MyStateObject(), 0, 5000);
        GC.KeepAlive(timer);
    }
}
4 голосов
/ 25 января 2009

Я думаю, что все в порядке, это поле private static вашего класса.

Я бы оставил эту ссылку как статическое поле, а не поиграл со сборщиком мусора.

...