iT邦幫忙

0

[WinForm][C#] 為什麼在threading .timer的callback會取到不同的thread ID

在做threading.timer測試時,發現在thread callback拿到1個ID以上.
理解上,應該只拿到自己的thread ID,怎麼會拿到一個以上呢?
https://ithelp.ithome.com.tw/upload/images/20180105/201067646xrY7zJc3I.png

using System.Threading;
        private  Timer timer;
        private void Form1_Load(object sender, EventArgs e)
        {
             TimerCallback callback = new  TimerCallback(Do);
             timer = new  Timer(callback, null, 0, 1000);

        }
        private void Do(object state)
        {
            //這裡會拿到不同的ID,為什麼?
            string val =  Thread.CurrentThread.ManagedThreadId.ToString();
            this.BeginInvoke(new dSetList(_setList), new object[] { val }); 

        }
        delegate void dSetList(string val);
        private void _setList(string val)
        {
            if (listBox1.Items.Contains(val) == false)
            {
                listBox1.Items.Add(val);
            }
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            string val = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
            textBox1.Text = val;
        }
看更多先前的討論...收起先前的討論...
weiclin iT邦高手 4 級 ‧ 2018-01-04 18:10:23 檢舉
http://jjnnykimo.pixnet.net/blog/post/21585481
圓頭人 iT邦新手 2 級 ‧ 2018-01-05 08:34:04 檢舉
抱歉,沒有表達清楚
這個提到會有2個線程
但我出現了3個線程.
Sean Liao iT邦新手 5 級 ‧ 2018-01-05 10:04:02 檢舉
System.Threading.Timer 利用了 thread pool 可用的執行緒來執行 callback,CLR 會自動選取的可用執行緒來執行。若你的 callback 方法所需時間大於你的 Timer 觸發週期,出現 2 個或以上的 ThreadId 都是優化的結果(盡可能讓工作一觸發就執行,而非加入等待被執行區)。
圓頭人 iT邦新手 2 級 ‧ 2018-01-05 13:16:28 檢舉
哦~原來如此啊~感謝大大
意思是說call back會交由有空的thread來做.
如果第一次觸發沒有做完,它就會加入等待被執行區,等著被執行.
第二次觸發的callback又被分配另一個thread來執行,所以才會有2個thread在運作callback
這樣理解正確嗎?

想到一個問題,那是誰new thread的呢?CLR嗎?

1 個回答

0
Sean Liao
iT邦新手 5 級 ‧ 2018-01-09 10:07:07
最佳解答

統一在這回答:

  1. 觸發後執行的方法若超出 timer 時間間隔,則該方法會持續佔用 Thread pool 中的某一執行緒;直到完成工作(非等待被執行)。而每次工作進來 CLR 會依照當前情況選擇池中有空閒的執行緒執行,即便執行方法所需時間小於 timer 時間間隔,也有可能會出現多個 Thread Id(不一定每次都選到同一個執行緒)。
  2. System.Threading.Timer 和 System.Timers.Timer 都使用了 Thread pool 中的執行緒,由 CLR 管理 pool 大小(有多少個工作執行緒)。隨著程式運行,CLR 會動態調整大小(新增或銷毀執行緒),這個好處是池中的執行緒可以被重複使用。

也可以手動指定池的大小:
https://msdn.microsoft.com/zh-tw/library/system.threading.threadpool.setmaxthreads(v=vs.110).aspx

更詳細的介紹可以看這篇:
http://www.c-sharpcorner.com/UploadFile/1d42da/threading-pooling-in-C-Sharp/

看更多先前的回應...收起先前的回應...
圓頭人 iT邦新手 2 級 ‧ 2018-01-09 11:28:19 檢舉

感謝大大~
看完觀念變得好清楚^^

可以說CLR會管理thread(新增刪除thread)
不過我們也可以新增thread下去跑,再由CLR來管理現在哪個thread要跑

Sean Liao iT邦新手 5 級 ‧ 2018-01-09 12:47:38 檢舉

如果是用 new Thread(()=>DoWork) 這種方式宣告的執行緒(非 ThreadPool),需要自行管理生命週期,該 Thread 結束後也無法重複使用。

而 Task, System.Timers.Timer, System.Threading.Timer 與 ThreadPool 相關的類別,才是供 CLR 管理。

圓頭人 iT邦新手 2 級 ‧ 2018-01-10 09:15:59 檢舉

感謝大大的說明,那new thread的部分
自行管理周期,是指所以我們new thread只會做我們指定的工作.
我們可以設定我們new 的thread誰要等誰t2.join()
那thread start後 t1.Start();
t1 DoWork結束後,還是會回到GC的機制,GC會判斷該thread工作已完成,會把t1的記憶體釋放,是嗎?

Sean Liao iT邦新手 5 級 ‧ 2018-01-10 09:46:32 檢舉

是的,沒錯。

我要發表回答

立即登入回答