而使用线程内存泄漏 [英] Memory leak while using Threads

查看:143
本文介绍了而使用线程内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎已经在这片code内存泄漏。它是一个控制台应用程序,它创建了几个类(的WorkerThread),每个写入控制台在指定的时间间隔。所述Threading.Timer是用来做此,因此,写入是在一个单独线程执行的控制台(所述TimerCallback被称为在从线程池所取的单独的线程)。更复杂的是,到FileSystemWatcher对象的Changed事件的MainThread类挂钩;当的test.xml文件的变化,的WorkerThread类是重新创建。

每个时刻的文件保存,(每次的的WorkerThread,因此定时器重建),在任务管理器中增加了内存(内存使用,有时也VM大小);此外,在.net内存分析器(V3.1),的的WorkerThread类增加两个实例未予(这可能是一个红色的鲱鱼,但因为我读过的.Net内存设置有一个bug由此挣扎检测处置类。

总之,这里的code - 没有人知道什么是错

修改:我搬到类创作出FileSystemWatcher.Changed事件处理程序,这意味着的WorkerThread类总是被在​​同一个线程创建的。我已经添加了一些保护的静态变量。我还提供线程信息,以更清楚地表明这是怎么回事,并使用定时器使用一个明确的主题已经被交换;然而,记忆依然漏水!内存使用增加缓慢所有的时间(这只是由于在控制台窗口中额外的文本?),当我更改文件虚拟机大小增加。这里是code中的最新版本:

修改这似乎主要与使用内存控制台的一个问题,因为你写它。还有用明确写入线程增加了内存使用量的问题。请参见下面我的答案。

 类节目
{
    私有静态列表<的WorkerThread>线程=新的名单,其中,的WorkerThread>();

    静态无效的主要(字串[] args)
    {
        MainThread.Start();

    }
}

公共类MainThread
{
    私有静态诠释_eventsRaised = 0;
    私有静态诠释_eventsRespondedTo = 0;
    私有静态布尔_reload = FALSE;
    私人静态只读对象_reloadLock =新的对象();
    //做一些曾经在处理器,虽然
    //这个code会去ONSTART在一个窗口服务。
    公共静态无效的开始()
    {
        的WorkerThread线程1 = NULL;
        的WorkerThread线程2 = NULL;

        Console.WriteLine(开始:线程+ Thread.CurrentThread.ManagedThreadId);
        //看配置
        FileSystemWatcher的观察家=新FileSystemWatcher的();
        watcher.Path =../../;
        watcher.Filter =的test.xml;
        watcher.EnableRaisingEvents = TRUE;
        //订阅更改事件。注意,这个事件可以被提出了许多次,每次保存文件。
        watcher.Changed + =(发件人,参数)=> FileChanged(发件人,参数);

        线程1 =新的WorkerThread(富,10);
        线程2 =新的WorkerThread(巴,15);

        而(真)
        {
            如果(_reload)
            {
                //创建两个线程。
                Console.WriteLine(开始 - 重装:线程+ Thread.CurrentThread.ManagedThreadId);
                //等待,使其他文件中更改的事件传递
                Console.WriteLine(开始 - 等待:线程+ Thread.CurrentThread.ManagedThreadId);
                thread1.Dispose();
                thread2.Dispose();
                Thread.sleep代码(3000); //每个线程持续0.5秒,所以3秒应该有大量等待
                                    // LoadData函数来完成。
                Monitor.Enter(_reloadLock);
                线程1 =新的WorkerThread(富,10);
                线程2 =新的WorkerThread(巴,15);
                _reload = FALSE;
                Monitor.Exit(_reloadLock);
            }
        }
    }

    //这个事件处理函数在一个单独的线程启动()
    静态无效FileChanged(对象源,FileSystemEventArgs E)
    {
        Monitor.Enter(_reloadLock);
        _eventsRaised + = 1;
        //如果是超过一秒自上次事件(也就是,这是一个新的保存),然后等待3秒钟(以避免
        处理前//多个事件为同一个文件保存)
        如果(!_reload)
        {
            Console.WriteLine(FileChanged:线程+ Thread.CurrentThread.ManagedThreadId);
            _eventsRespondedTo + = 1;
            Console.WriteLine(FileChanged处理的事件{0} {1}的。,_eventsRespondedTo,_eventsRaised);
            //告诉主线程启动线程
            _reload = TRUE;
        }
        Monitor.Exit(_reloadLock);
    }
}

公共类的WorkerThread:IDisposable的
{
    私人System.Threading.Timer定时器; //定时器存在于它自己单独的线程池线程。
    私人字符串_name =的String.Empty;
    私人诠释_interval = 0; //在毫秒线程等待时间。
    私人螺纹_Thread = NULL;
    私人的ThreadStart _job = NULL;

    公众的WorkerThread(字符串名称,诠释间隔)
    {
        Console.WriteLine(的WorkerThread:线程+ Thread.CurrentThread.ManagedThreadId);
        _name =名称;
        _interval =间隔* 1000;
        _job =新的ThreadStart(LoadData);
        _Thread =新主题(_job);
        _thread.Start();
        //定时器=新的定时器(蜱,空,1000,间隔* 1000);
    }

    //此委托实例并不在同一个线程创建计时器的线程中运行。它运行在其自己的
    //线程,从线程池拍摄。因此,没有必要创建为LoadData方法一个新的线程。
    私人无效蜱(对象状态)
    {
        // LoadData();
    }

    //加载数据。从单独的线程调用。持续0.5秒。
    //
    //私人无效LoadData(对象状态)
    私人无效LoadData()
    {
        而(真)
        {
            的for(int i = 0;我小于10;我++)
            {
                Console.WriteLine(的String.Format(工人线程{0}({2}):{1},_name,我,Thread.CurrentThread.ManagedThreadId));
                Thread.sleep代码(50);
            }
            Thread.sleep代码(_interval);
        }
    }

    公共无效停止()
    {
        Console.WriteLine(停止:线程+ Thread.CurrentThread.ManagedThreadId);
        //timer.Dispose();
        _thread.Abort();
    }


    #地区IDisposable的成员

    公共无效的Dispose()
    {
        Console.WriteLine(处置:线程+ Thread.CurrentThread.ManagedThreadId);
        //timer.Dispose();
        _thread.Abort();
    }

    #endregion
}
 

解决方案

嗯,有过一些时间来研究这再次,看来内存泄漏是有点红鲱鱼。的当我停止写入控制台,内存使用量停止增加的。

然而,在一个尚未解决的问题每次我编辑的test.xml文件(触发Changed事件的FileSystemWatcher的,其处理程序设置标志,导致工人类续约,因此线程/定时器是时间停止),约4K内存的增加,前提是我使用明确的主题,而计时器。当我使用一个定时器,是没有问题的。但是,由于我宁愿用一个定时器不是一个线程,这不再是一个问题,但我仍然有兴趣,为什么它正在发生。

请参阅新的code以下。我创建了两个类 - 的WorkerThread和WorkerTimer,其中一个使用线程和其他计时器(我试过两个定时器,分别System.Threading.Timer和System.Timers.Timer的与控制台输出打开,你。可以看到其中的差别,这使得与哪个线程Tick事件引发的)的问候。只是注释/取消注释MainThread.Start的相应行,以使用所需的类。基于上述原因,建议Console.WriteLine命令行注释掉,当你要检查,一切都按预期工作的除外。

 类节目
{
    静态无效的主要(字串[] args)
    {
        MainThread.Start();

    }
}

公共类MainThread
{
    私有静态诠释_eventsRaised = 0;
    私有静态诠释_eventsRespondedTo = 0;
    私有静态布尔_reload = FALSE;
    私人静态只读对象_reloadLock =新的对象();
    //做一些曾经在处理器,虽然
    //这个code会去ONSTART在一个窗口服务。
    公共静态无效的开始()
    {
        的WorkerThread线程1 = NULL;
        的WorkerThread线程2 = NULL;
        // WorkerTimer线程1 = NULL;
        // WorkerTimer线程2 = NULL;

        //Console.WriteLine("Start:线程+ Thread.CurrentThread.ManagedThreadId);
        //看配置
        FileSystemWatcher的观察家=新FileSystemWatcher的();
        watcher.Path =../../;
        watcher.Filter =的test.xml;
        watcher.EnableRaisingEvents = TRUE;
        //订阅更改事件。注意,这个事件可以被提出了许多次,每次保存文件。
        watcher.Changed + =(发件人,参数)=> FileChanged(发件人,参数);

        线程1 =新的WorkerThread(富,10);
        线程2 =新的WorkerThread(巴,15);
        //线程1 =新WorkerTimer(富,10);
        //线程2 =新WorkerTimer(巴,15);

        而(真)
        {
            如果(_reload)
            {
                //创建两个线程。
                //Console.WriteLine("Start  - 重装:线程+ Thread.CurrentThread.ManagedThreadId);
                //等待,使其他文件中更改的事件传递
                //Console.WriteLine("Start  - 等待:线程+ Thread.CurrentThread.ManagedThreadId);
                thread1.Dispose();
                thread2.Dispose();
                Thread.sleep代码(3000); //每个线程持续0.5秒,所以3秒应该有大量等待
                // LoadData函数来完成。
                Monitor.Enter(_reloadLock);
                //GC.Collect();
                线程1 =新的WorkerThread(富,5);
                线程2 =新的WorkerThread(酒吧,7);
                //线程1 =新WorkerTimer(富,5);
                //线程2 =新WorkerTimer(酒吧,7);
                _reload = FALSE;
                Monitor.Exit(_reloadLock);
            }
        }
    }

    //这个事件处理函数在一个单独的线程启动()
    静态无效FileChanged(对象源,FileSystemEventArgs E)
    {
        Monitor.Enter(_reloadLock);
        _eventsRaised + = 1;
        //如果是超过一秒自上次事件(也就是,这是一个新的保存),然后等待3秒钟(以避免
        处理前//多个事件为同一个文件保存)
        如果(!_reload)
        {
            //Console.WriteLine("FileChanged:线程+ Thread.CurrentThread.ManagedThreadId);
            _eventsRespondedTo + = 1;
            。//Console.WriteLine("FileChanged处理的事件{0} {1},_eventsRespondedTo,_eventsRaised的)。
            //告诉主线程启动线程
            _reload = TRUE;
        }
        Monitor.Exit(_reloadLock);
    }
}

公共类WorkerTimer:IDisposable的
{
    私人System.Threading.Timer _timer; //定时器存在于它自己单独的线程池线程。
    //私人System.Timers.Timer的_timer;
    私人字符串_name =的String.Empty;

    ///<总结>
    ///初始化℃的新的实例;参见CREF =的WorkerThread/>类。
    ///< /总结>
    ///<参数名称=名称>该名称与LT; /参数>
    ///< PARAM NAME =间隔>在时间间隔,以秒-1; /参数>
    公共WorkerTimer(字符串名称,诠释间隔)
    {
        _name =名称;
        //Console.WriteLine("WorkerThread构造:从线程调用+ Thread.CurrentThread.ManagedThreadId);
        // _定时器=新System.Timers.Timer的(间隔* 1000);
        //_timer.Elapsed + =(发件人,参数)=> LoadData();
        // _ timer.Start();
        _timer =新的定时器(蜱,空,1000,间隔* 1000);
    }

    //此委托实例并不在同一个线程创建计时器的线程中运行。它运行在其自己的
    //线程,从线程池拍摄。因此,没有必要创建为LoadData方法一个新的线程。
    私人无效蜱(对象状态)
    {
        LoadData();
    }

    //加载数据。从单独的线程调用。持续0.5秒。
    //
    私人无效LoadData()
    {
        的for(int i = 0;我小于10;我++)
        {
            //Console.WriteLine(string.Format("Worker螺纹{0}({2}):{1},_name,I,Thread.CurrentThread.ManagedThreadId));
            Thread.sleep代码(50);
        }
    }

    公共无效停止()
    {
        //Console.WriteLine("Stop:从线程+ Thread.CurrentThread.ManagedThreadId)调用;
        // _ timer.Stop();
        _timer.Change(Timeout.Infinite,Timeout.Infinite);
        // _定时器= NULL;
        // _ timer.Dispose();
    }


    #地区IDisposable的成员

    公共无效的Dispose()
    {
        //Console.WriteLine("Dispose:所谓的线程+ Thread.CurrentThread.ManagedThreadId);
        // _ timer.Stop();
        _timer.Change(Timeout.Infinite,Timeout.Infinite);
        // _定时器= NULL;
        // _ timer.Dispose();
    }

    #endregion
}

公共类的WorkerThread:IDisposable的
{
    私人字符串_name =的String.Empty;
    私人诠释_interval = 0; //在毫秒线程等待时间。
    私人螺纹_Thread = NULL;
    私人的ThreadStart _job = NULL;
    私有对象_syncObject =新的对象();
    私人布尔_killThread = FALSE;

    公众的WorkerThread(字符串名称,诠释间隔)
    {
        _name =名称;
        _interval =间隔* 1000;
        _job =新的ThreadStart(LoadData);
        _Thread =新主题(_job);
        //Console.WriteLine("WorkerThread构造函数:线程+ _thread.ManagedThreadId +从创建线程+ Thread.CurrentThread.ManagedThreadId)调用;
        _thread.Start();
    }

    //加载数据。从单独的线程调用。持续0.5秒。
    //
    //私人无效LoadData(对象状态)
    私人无效LoadData()
    {
        而(真)
        {
            //检查,看看是否线程它停止。
            布尔isKilled = FALSE;

            锁定(_syncObject)
            {
                isKilled = _killThread;
            }

            如果(isKilled)
                返回;

            的for(int i = 0;我小于10;我++)
            {
                //Console.WriteLine(string.Format("Worker螺纹{0}({2}):{1},_name,I,Thread.CurrentThread.ManagedThreadId));
                Thread.sleep代码(50);
            }
            Thread.sleep代码(_interval);
        }
    }

    公共无效停止()
    {
        //Console.WriteLine("Stop:线程+ _thread.ManagedThreadId +之称的线程+ Thread.CurrentThread.ManagedThreadId);
        // _ Thread.Abort的();
        锁定(_syncObject)
        {
            _killThread = TRUE;
        }
        _thread.Join();
    }


    #地区IDisposable的成员

    公共无效的Dispose()
    {
        //Console.WriteLine("Dispose:线程+ _thread.ManagedThreadId +之称的线程+ Thread.CurrentThread.ManagedThreadId);
        // _ Thread.Abort的();
        锁定(_syncObject)
        {
            _killThread = TRUE;
        }
        _thread.Join();
    }

    #endregion
}
 

I appear to have a memory leak in this piece of code. It is a console app, which creates a couple of classes (WorkerThread), each of which writes to the console at specified intervals. The Threading.Timer is used to do this, hence writing to the console is performed in a separate thread (the TimerCallback is called in a seperate thread taken from the ThreadPool). To complicate matters, the MainThread class hooks on to the Changed event of the FileSystemWatcher; when the test.xml file changes, the WorkerThread classes are recreated.

Each time the file is saved, (each time that the WorkerThread and therefore the Timer is recreated), the memory in the Task Manager increases (Mem Usage, and sometimes also VM Size); furthermore, in .Net Memory Profiler (v3.1), the Undisposed Instances of the WorkerThread class increases by two (this may be a red herring though, because I've read that .Net Memory Profiler had a bug whereby it struggled to detect disposed classes.

Anyway, here's the code - does anyone know what's wrong?

EDIT: I've moved the class creation out of the FileSystemWatcher.Changed event handler, meaning that the WorkerThread classes are always being created in the same thread. I've added some protection to the static variables. I've also provided threading information to show more clearly what's going on, and have been interchanging using the Timer with using an explicit Thread; however, the memory is still leaking! The Mem Usage increases slowly all the time (is this simply due to extra text in the console window?), and the VM Size increases when I change the file. Here is the latest version of the code:

EDIT This appears to be primarily a problem with the console using up memory, as you write to it. There is still a problem with explicitly written Threads increasing the memory usage. See my answer below.

class Program
{
    private static List<WorkerThread> threads = new List<WorkerThread>();

    static void Main(string[] args)
    {
        MainThread.Start();

    }
}

public class MainThread
{
    private static int _eventsRaised = 0;
    private static int _eventsRespondedTo = 0;
    private static bool _reload = false;
    private static readonly object _reloadLock = new object();
    //to do something once in handler, though
    //this code would go in onStart in a windows service.
    public static void Start()
    {
        WorkerThread thread1 = null;
        WorkerThread thread2 = null;

        Console.WriteLine("Start: thread " + Thread.CurrentThread.ManagedThreadId);
        //watch config
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = "../../";
        watcher.Filter = "test.xml";
        watcher.EnableRaisingEvents = true;
        //subscribe to changed event. note that this event can be raised a number of times for each save of the file.
        watcher.Changed += (sender, args) => FileChanged(sender, args);

        thread1 = new WorkerThread("foo", 10);
        thread2 = new WorkerThread("bar", 15);

        while (true)
        {
            if (_reload)
            {
                //create our two threads.
                Console.WriteLine("Start - reload: thread " + Thread.CurrentThread.ManagedThreadId);
                //wait, to enable other file changed events to pass
                Console.WriteLine("Start - waiting: thread " + Thread.CurrentThread.ManagedThreadId);
                thread1.Dispose();
                thread2.Dispose();
                Thread.Sleep(3000); //each thread lasts 0.5 seconds, so 3 seconds should be plenty to wait for the 
                                    //LoadData function to complete.
                Monitor.Enter(_reloadLock);
                thread1 = new WorkerThread("foo", 10);
                thread2 = new WorkerThread("bar", 15);
                _reload = false;
                Monitor.Exit(_reloadLock);
            }
        }
    }

    //this event handler is called in a separate thread to Start()
    static void FileChanged(object source, FileSystemEventArgs e)
    {
        Monitor.Enter(_reloadLock);
        _eventsRaised += 1;
        //if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid 
        //multiple events for the same file save) before processing
        if (!_reload)
        {
            Console.WriteLine("FileChanged: thread " + Thread.CurrentThread.ManagedThreadId);
            _eventsRespondedTo += 1;
            Console.WriteLine("FileChanged. Handled event {0} of {1}.", _eventsRespondedTo, _eventsRaised);
            //tell main thread to restart threads
            _reload = true;
        }
        Monitor.Exit(_reloadLock);
    }
}

public class WorkerThread : IDisposable
{
    private System.Threading.Timer timer;   //the timer exists in its own separate thread pool thread.
    private string _name = string.Empty;
    private int _interval = 0;  //thread wait interval in ms.
    private Thread _thread = null;
    private ThreadStart _job = null;

    public WorkerThread(string name, int interval)
    {
        Console.WriteLine("WorkerThread: thread " + Thread.CurrentThread.ManagedThreadId);
        _name = name;
        _interval = interval * 1000;
        _job = new ThreadStart(LoadData);
        _thread = new Thread(_job);
        _thread.Start();
        //timer = new Timer(Tick, null, 1000, interval * 1000);
    }

    //this delegate instance does NOT run in the same thread as the thread that created the timer. It runs in its own
    //thread, taken from the ThreadPool. Hence, no need to create a new thread for the LoadData method.
    private void Tick(object state)
    {
        //LoadData();
    }

    //Loads the data. Called from separate thread. Lasts 0.5 seconds.
    //
    //private void LoadData(object state)
    private void LoadData()
    {
        while (true)
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(string.Format("Worker thread {0} ({2}): {1}", _name, i, Thread.CurrentThread.ManagedThreadId));
                Thread.Sleep(50);
            }
            Thread.Sleep(_interval);
        }
    }

    public void Stop()
    {
        Console.WriteLine("Stop: thread " + Thread.CurrentThread.ManagedThreadId);
        //timer.Dispose();
        _thread.Abort();
    }


    #region IDisposable Members

    public void Dispose()
    {
        Console.WriteLine("Dispose: thread " + Thread.CurrentThread.ManagedThreadId);
        //timer.Dispose();
        _thread.Abort();
    }

    #endregion
}

解决方案

Well, having had some time to look into this again, it appears that the memory leak is a bit of a red herring. When I stop writing to the console, the memory usage stops increasing.

However, there is a remaining issue in that every time I edit the test.xml file (which fires the Changed event on the FileSystemWatcher, whose handler sets flags that cause the worker classes to be renewed and therefore threads/timers to be stopped), the memory increases by about 4K, providing that I am using explicit Threads, rather Timers. When I use a Timer, there is no problem. But, given that I would rather use a Timer than a Thread, this is no longer an issue to me, but I would still be interested in why it is occuring.

See the new code below. I've created two classes - WorkerThread and WorkerTimer, one of which uses Threads and the other Timers (I've tried two Timers, the System.Threading.Timer and the System.Timers.Timer. with the Console output switched on, you can see the difference that this makes with regards to which thread the tick event is raised on). Just comment/uncomment the appropriate lines of MainThread.Start in order to use the required class. For the reason above, it is recommended that the Console.WriteLine lines are commented out, except when you want to check that everything is working as expected.

class Program
{
    static void Main(string[] args)
    {
        MainThread.Start();

    }
}

public class MainThread
{
    private static int _eventsRaised = 0;
    private static int _eventsRespondedTo = 0;
    private static bool _reload = false;
    private static readonly object _reloadLock = new object();
    //to do something once in handler, though
    //this code would go in onStart in a windows service.
    public static void Start()
    {
        WorkerThread thread1 = null;
        WorkerThread thread2 = null;
        //WorkerTimer thread1 = null;
        //WorkerTimer thread2 = null;

        //Console.WriteLine("Start: thread " + Thread.CurrentThread.ManagedThreadId);
        //watch config
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = "../../";
        watcher.Filter = "test.xml";
        watcher.EnableRaisingEvents = true;
        //subscribe to changed event. note that this event can be raised a number of times for each save of the file.
        watcher.Changed += (sender, args) => FileChanged(sender, args);

        thread1 = new WorkerThread("foo", 10);
        thread2 = new WorkerThread("bar", 15);
        //thread1 = new WorkerTimer("foo", 10);
        //thread2 = new WorkerTimer("bar", 15);

        while (true)
        {
            if (_reload)
            {
                //create our two threads.
                //Console.WriteLine("Start - reload: thread " + Thread.CurrentThread.ManagedThreadId);
                //wait, to enable other file changed events to pass
                //Console.WriteLine("Start - waiting: thread " + Thread.CurrentThread.ManagedThreadId);
                thread1.Dispose();
                thread2.Dispose();
                Thread.Sleep(3000); //each thread lasts 0.5 seconds, so 3 seconds should be plenty to wait for the 
                //LoadData function to complete.
                Monitor.Enter(_reloadLock);
                //GC.Collect();
                thread1 = new WorkerThread("foo", 5);
                thread2 = new WorkerThread("bar", 7);
                //thread1 = new WorkerTimer("foo", 5);
                //thread2 = new WorkerTimer("bar", 7);
                _reload = false;
                Monitor.Exit(_reloadLock);
            }
        }
    }

    //this event handler is called in a separate thread to Start()
    static void FileChanged(object source, FileSystemEventArgs e)
    {
        Monitor.Enter(_reloadLock);
        _eventsRaised += 1;
        //if it was more than a second since the last event (ie, it's a new save), then wait for 3 seconds (to avoid 
        //multiple events for the same file save) before processing
        if (!_reload)
        {
            //Console.WriteLine("FileChanged: thread " + Thread.CurrentThread.ManagedThreadId);
            _eventsRespondedTo += 1;
            //Console.WriteLine("FileChanged. Handled event {0} of {1}.", _eventsRespondedTo, _eventsRaised);
            //tell main thread to restart threads
            _reload = true;
        }
        Monitor.Exit(_reloadLock);
    }
}

public class WorkerTimer : IDisposable
{
    private System.Threading.Timer _timer;   //the timer exists in its own separate thread pool thread.
    //private System.Timers.Timer _timer;
    private string _name = string.Empty;

    /// <summary>
    /// Initializes a new instance of the <see cref="WorkerThread"/> class.
    /// </summary>
    /// <param name="name">The name.</param>
    /// <param name="interval">The interval, in seconds.</param>
    public WorkerTimer(string name, int interval)
    {
        _name = name;
        //Console.WriteLine("WorkerThread constructor: Called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_timer = new System.Timers.Timer(interval * 1000);
        //_timer.Elapsed += (sender, args) => LoadData();
        //_timer.Start();
        _timer = new Timer(Tick, null, 1000, interval * 1000);
    }

    //this delegate instance does NOT run in the same thread as the thread that created the timer. It runs in its own
    //thread, taken from the ThreadPool. Hence, no need to create a new thread for the LoadData method.
    private void Tick(object state)
    {
        LoadData();
    }

    //Loads the data. Called from separate thread. Lasts 0.5 seconds.
    //
    private void LoadData()
    {
        for (int i = 0; i < 10; i++)
        {
            //Console.WriteLine(string.Format("Worker thread {0} ({2}): {1}", _name, i, Thread.CurrentThread.ManagedThreadId));
            Thread.Sleep(50);
        }
    }

    public void Stop()
    {
        //Console.WriteLine("Stop: called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_timer.Stop();
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
        //_timer = null;
        //_timer.Dispose();
    }


    #region IDisposable Members

    public void Dispose()
    {
        //Console.WriteLine("Dispose: called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_timer.Stop();
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
        //_timer = null;
        //_timer.Dispose();
    }

    #endregion
}

public class WorkerThread : IDisposable
{
    private string _name = string.Empty;
    private int _interval = 0;  //thread wait interval in ms.
    private Thread _thread = null;
    private ThreadStart _job = null;
    private object _syncObject = new object();
    private bool _killThread = false;

    public WorkerThread(string name, int interval)
    {
        _name = name;
        _interval = interval * 1000;
        _job = new ThreadStart(LoadData);
        _thread = new Thread(_job);
        //Console.WriteLine("WorkerThread constructor: thread " + _thread.ManagedThreadId + " created. Called from thread " + Thread.CurrentThread.ManagedThreadId);
        _thread.Start();
    }

    //Loads the data. Called from separate thread. Lasts 0.5 seconds.
    //
    //private void LoadData(object state)
    private void LoadData()
    {
        while (true)
        {
            //check to see if thread it to be stopped.
            bool isKilled = false;

            lock (_syncObject)
            {
                isKilled = _killThread;
            }

            if (isKilled)
                return;

            for (int i = 0; i < 10; i++)
            {
                //Console.WriteLine(string.Format("Worker thread {0} ({2}): {1}", _name, i, Thread.CurrentThread.ManagedThreadId));
                Thread.Sleep(50);
            }
            Thread.Sleep(_interval);
        }
    }

    public void Stop()
    {
        //Console.WriteLine("Stop: thread " + _thread.ManagedThreadId + " called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_thread.Abort();
        lock (_syncObject)
        {
            _killThread = true;
        }
        _thread.Join();
    }


    #region IDisposable Members

    public void Dispose()
    {
        //Console.WriteLine("Dispose: thread " + _thread.ManagedThreadId + " called from thread " + Thread.CurrentThread.ManagedThreadId);
        //_thread.Abort();
        lock (_syncObject)
        {
            _killThread = true;
        }
        _thread.Join();
    }

    #endregion
}

这篇关于而使用线程内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆