C# 線程的掛起與恢復

jopen 9年前發布 | 3K 次閱讀 C#

我本質是不希望有人去掛起或恢復線程的,因為沒人知道線程到底執行到了那里,

掛起線程后再恢復線程可能會造成某些問題,然后你容易無法解決它,所以微軟

如今是把Thread.Resume()與Thread.Suspend()過時,不久以后會移除出.NET庫

但是移除你就無法掛起或恢復了嗎?我想是不可能 畢竟辦法如此之多 好了我們回

到正題 如果你有必要這樣做我也希望你們用AutoResetEvent(自動重置單事件對象)

的配合,因為它會很安全 但是能否夠安全還需要具體看開發者自己的代碼如何寫的。


        private void Form1_Load(object sender, EventArgs e)
        {
            Thread fd_thr = new Thread(this.FileDownload);
            fd_thr.Start();
            fd_thr.Suspend(); // 掛起線程, 過時
            fd_thr.Resume();  // 恢復線程, 過時
        }

        private void FileDownload()
        {
            byte[] buffer = null;
            using (WebClient client = new WebClient())
                buffer = client.DownloadData("http://www.baidu.com");
            Console.WriteLine(Encoding.UTF8.GetString(buffer));
        }
下面的代碼,貌似沒有問題,但你可能會在輸出面板會出現一句錯誤“引發的異常:


“System.IO.IOException”(位于 mscorlib.dll 中)”那么這就會涉及到一個問題,我本

人是討厭代碼拋出錯誤的,首先你要知道一但拋出錯誤意味著無法釋放資源且不

說最重要拋出錯誤的頻率過高你的程序意味著穩定性極差不一會可能就會自己掛

掉,每次拋出錯誤意味著一次堆棧溢出,try catch盡量少用,為什么需要自己體會


        private AutoResetEvent fd_thr_supend = new AutoResetEvent(false);

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread fd_thr = new Thread(this.FileDownload);
            fd_thr.Start();
            this.fd_thr_supend.Reset(); // 掛起線程
            this.fd_thr_supend.Set(); // 恢復線程
        }

        private void FileDownload()
        {
            byte[] buffer = null;
            using (WebClient client = new WebClient())
                buffer = client.DownloadData("http://www.baidu.com");
            this.fd_thr_supend.WaitOne(); // 阻塞,等待信號
            Console.WriteLine(Encoding.UTF8.GetString(buffer));
        }
上面則配合AutoResetEvent方式配合進行線程的掛起或恢復,這樣做有利代碼的


安全與減少發生錯誤的幾率,因為你不是真正的把線程掛起而是阻塞線程 那么一

旦發生錯誤 你可以盡早的排查錯誤,而不是因為Thread.Resume()與Thread.Sus

pend()方式一掛起,一旦發生錯誤你根本找不到錯誤的原因,大大的增加了穩定

性與安全性。

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern int GetCurrentThreadId();

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern int SuspendThread(IntPtr hThread);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern uint ResumeThread(IntPtr hThread);

        public int hCurrenthThreadId;

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenThread(int dwDesiredAccess, bool bInheritHandle, uint dwThreadId);

        public const int THREADACCESS_SUSPEND_RESUME = 0x0002;

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread fd_thr = new Thread(this.FileDownload);
            fd_thr.Start();
            while (this.hCurrenthThreadId == 0); // 等待線程被啟動
            IntPtr hCurrenthThread = OpenThread(THREADACCESS_SUSPEND_RESUME, false, (uint)this.hCurrenthThreadId);
            // 掛起線程
            SuspendThread(hCurrenthThread);
            // 恢復線程
            ResumeThread(hCurrenthThread); 
        }

        private void FileDownload()
        {
            this.hCurrenthThreadId = GetCurrentThreadId();
            byte[] buffer = null;
            using (WebClient client = new WebClient())
                buffer = client.DownloadData("http://www.baidu.com");
            Console.WriteLine(Encoding.UTF8.GetString(buffer));
        }
上面的方法也不安全,因為上面的做法其實與Thread.Resume()與Thread.Suspend()兩個函數的


功能差不多,不過是用于代替過時命令的一種Winapi方案,當然還有一些辦法。總之掛起或恢復

一個線程的辦法并不少 上面的三種方法其實都可以 不過需要考慮穩定性才是真。



 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!