none
請教執行緒問題? RRS feed

  • 問題

  • 如果我有一主程式~其他的都是類別~ 在主程式中呼叫執行緒  ~ 之前我試過可以呼叫有傳參數的方法 ~ 但是用執行緒呼叫 有 return 的方法就會出錯 

    如果我今天執行緒呼叫的方法不是return方法 ~但是 內容中有用到其他有return 的方法 ~ 那用執行緒呼叫此方法會有甚麼問題嗎?

    有什麼方法能達這樣的目的?  因為有一些功能必須要像別的類別來取某些值使用~但是又要寫成執行緒的方式~感覺腦袋有點轉不過來~

    因為想讓主程式開啟後 能同時叫起其他程式自行執行 不用互相等待 ~ 但是有些功能必須用到像別人取值 就轉不過來~  
    2009年7月21日 上午 05:52

解答

  • 執行緒本身是獨立的,自己不能 return 給別的執行緒,但是執行緒裡面可以呼叫其他類別方法,接受該方法的 return ,比如說 Math.Sqrt。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    • 已標示為解答 Q楓仔Q 2009年7月21日 上午 06:29
    2009年7月21日 上午 05:57
  • 你就把二條執行緒(多條亦然)想成是平行線,在平行線內的程式,共享一個記憶體空間,所以在執行緒內的程式可以使用 return 來抓取回傳值,但在不同的記憶體空間中你不能這樣做。
    這時你要去想有沒有方法讓兩條執行緒有一個可以共用的記憶體空間,然後透過這個空間來交換資料,而且還要保持 thread-safe 的情況來避免 race condition (兩個執行緒同時存取共用空間造成資料不同步)的問題。
    小人物一枚。
    • 已標示為解答 Q楓仔Q 2009年7月21日 上午 06:29
    2009年7月21日 上午 06:07
    版主
  • 只是為了方便說明, 會將Application啟動的稱為主執行緒. 而其它再產生的稱為次執行緒或子執行緒.
    想要多瞭解的話, 就要多爬文, MSDN 文件庫有相當多關於執行緒的文章. 我也是看那個學的.

    補充說明:
    我上次不是有貼這個連結? [建立執行緒並在啟動時間傳遞資料 ]
    裡面不是有提到下面這段話?你這樣的問法, 讓我感覺我幫你找這些資料好像是浪費時間.
    ===========================================================
    將資料傳遞給執行緒以及擷取來自執行緒的資料

    在 .NET Framework 2.0 版中,當您呼叫 Thread.Start 方法多載時,ParameterizedThreadStart 委派可讓您輕鬆地將含有資料的物件傳遞給執行緒。如需程式碼範例,請參閱 ParameterizedThreadStart

    使用 ParameterizedThreadStart 委派並不是傳遞資料的型別安全方式,因為 Thread. Start 方法多載會接受任何物件。替代方案是在 Helper 類別中封裝執行緒程序和資料,並使用 ThreadStart 委派來執行執行緒程序。下列兩個程式碼範例將會示範這項技術。

    這些委派都不具有傳回值,因為沒有地方可供傳回來自非同步呼叫的資料若要擷取執行緒方法的結果,可以依照第二個程式碼範例所示,使用回呼 (Callback) 方法。

    ==========================================================
    你看到粗體這部份, 就可以去爬文看一下有關於CallBack的說明, 例如:
    [事件和回呼 ]
    [回呼函式 ]
    [HOW TO:實作回呼函式 ]
    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    2009年7月21日 上午 06:56
    版主
  • 1. 定義委派 public delegate void ExampleCallback(int lineCount);
    2. 定義類別中的私有委派攔位 private ExampleCallback callback;
    3. 定義ThreadWithState建構函式,會傳入委派 public ThreadWithState(string text, int number, ExampleCallback callbackDelegate) 
    並將傳入的委派指派給callback
      callback = callbackDelegate;
    4.      呼叫委派  callback(1);    
    5. 註冊委派要呼叫的Function ->  ThreadWithState tws = new ThreadWithState("This report displays the number {0}.", 42, new ExampleCallback(ResultCallback));

           public static void ResultCallback(int lineCount)   
            {
                Console.WriteLine("Independent task printed {0} lines.", lineCount);
            }
    步驟五就是為了把   public static void ResultCallback(int lineCount)    傳給  public ThreadWithState
    所以 callback(1)=ResultCallback(1)



    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    • 已標示為解答 Q楓仔Q 2009年7月23日 上午 03:14
    2009年7月22日 上午 08:51
    版主

所有回覆

  • 執行緒本身是獨立的,自己不能 return 給別的執行緒,但是執行緒裡面可以呼叫其他類別方法,接受該方法的 return ,比如說 Math.Sqrt。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    • 已標示為解答 Q楓仔Q 2009年7月21日 上午 06:29
    2009年7月21日 上午 05:57
  • 你就把二條執行緒(多條亦然)想成是平行線,在平行線內的程式,共享一個記憶體空間,所以在執行緒內的程式可以使用 return 來抓取回傳值,但在不同的記憶體空間中你不能這樣做。
    這時你要去想有沒有方法讓兩條執行緒有一個可以共用的記憶體空間,然後透過這個空間來交換資料,而且還要保持 thread-safe 的情況來避免 race condition (兩個執行緒同時存取共用空間造成資料不同步)的問題。
    小人物一枚。
    • 已標示為解答 Q楓仔Q 2009年7月21日 上午 06:29
    2009年7月21日 上午 06:07
    版主
  • 這是上次問的執行緒問題~Bill大給了回答範例~

    Bill大的回答我有懂大致上的意思 ~  不太了解這樣的寫法等同return的方式嗎 ?~

    所以對於第2項 只懂大致上的意思不了解為何要這樣寫  ~ 這樣等同return嗎 ?~ 因為我沒用過這種寫法  所以想多了解一點




    1. Work class 用 ParameterizedThreadStart 委派 , 注意傳入參數一定得用 Object型別
    2. Work1 class 用封裝執行緒程序和資料方式來傳遞並以回呼方式接收資料
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;

    namespace ThreadTest_0
    {
        public partial class Form1 : Form
        {
            public delegate void myCallback(int i);

            public Form1()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                Work threadWork = new Work();
                Thread newThread = new Thread(threadWork.DoWork);
                              
                newThread.Start(1);

                Work1 threadWork1 = new Work1(2, new myCallback(ReturnCode));
                Thread newThread1 = new Thread(threadWork1.DoWork);
                newThread1.Start();
            }

            public void ReturnCode(int i)
            {
                MessageBox.Show("回傳" + i.ToString());
            }

            class Work
            {
            
                public void DoWork(object i)
     
                {
                    MessageBox.Show(i.ToString());
                }
            }


            class Work1
            {
                private myCallback callback0;
                private int iNo;
                public Work1(int i,myCallback callback1)
                {
                    iNo = i;
                    callback0 = callback1;
                }

                public void DoWork()
                {
                    MessageBox.Show(iNo.ToString());
                    if (callback0 != null)
                    {
                        callback0(iNo + 10);
                    }

                }

             }
        }
    }


    再另回答中也提到
    委派在這邊不過就是把
    public void ReturnCode(int i)
            {
                MessageBox.Show("回傳" + i.ToString());
            }
    這個function 傳給次執行緒去呼叫
    所以當執行到 callback0(iNo + 10); 這邊,實際上就等於在主執行緒呼叫 ReturnCode(2+10)

    主執行緒跟次執行緒如何區分?  他們不是平行的嗎?
    2009年7月21日 上午 06:37
  • 只是為了方便說明, 會將Application啟動的稱為主執行緒. 而其它再產生的稱為次執行緒或子執行緒.
    想要多瞭解的話, 就要多爬文, MSDN 文件庫有相當多關於執行緒的文章. 我也是看那個學的.

    補充說明:
    我上次不是有貼這個連結? [建立執行緒並在啟動時間傳遞資料 ]
    裡面不是有提到下面這段話?你這樣的問法, 讓我感覺我幫你找這些資料好像是浪費時間.
    ===========================================================
    將資料傳遞給執行緒以及擷取來自執行緒的資料

    在 .NET Framework 2.0 版中,當您呼叫 Thread.Start 方法多載時,ParameterizedThreadStart 委派可讓您輕鬆地將含有資料的物件傳遞給執行緒。如需程式碼範例,請參閱 ParameterizedThreadStart

    使用 ParameterizedThreadStart 委派並不是傳遞資料的型別安全方式,因為 Thread. Start 方法多載會接受任何物件。替代方案是在 Helper 類別中封裝執行緒程序和資料,並使用 ThreadStart 委派來執行執行緒程序。下列兩個程式碼範例將會示範這項技術。

    這些委派都不具有傳回值,因為沒有地方可供傳回來自非同步呼叫的資料若要擷取執行緒方法的結果,可以依照第二個程式碼範例所示,使用回呼 (Callback) 方法。

    ==========================================================
    你看到粗體這部份, 就可以去爬文看一下有關於CallBack的說明, 例如:
    [事件和回呼 ]
    [回呼函式 ]
    [HOW TO:實作回呼函式 ]
    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    2009年7月21日 上午 06:56
    版主
  • 可以建議一些Bill大看過的覺得不錯的嗎?

    MSDN的內容我有看過 ~ 一些部落格和網頁相關的內容我也有看 ~ 書上有寫執行緒的也比較少 ~

    可能有漏掉重要的部分~能請Bill大推薦一些不錯的資料嗎 ~ 很想把執行緒學好~"~

    2009年7月21日 上午 07:32
  • 有一本侯捷翻的 Multithreading Applications in Win32 很讚,不過 .Net 包裝太好了,這本過於接近底層,以現在的角度來看,當故事書看比較好,不過看這本也比較容易瞭解 Thread 封裝對應的意義。

    程式實作的想法,通常是由實際的狀況轉變來的。

    你先想一個問題,你是老師 (主執行緒),交代一班小朋友 (執行緒們) 去打掃教室及外圍區域。

    通常命令發布後,就是置後不理,直到每個小朋友來回報工作完成 (執行緒狀態為結束) ,執行緒間的關係只能透過執行緒狀態來瞭解是執行中、結束、暫停等。

    好,現在交代小朋友打掃的結果寫在黑板上,這就是共用記憶體,所以老師看、小朋友寫,是最簡單的,用個 List 或 Object Array 來放執行緒完成的結果,而用執行緒狀態或是 Join 來輪詢或等代小朋友完成。

    用實例來幻想,執行緒就不會那麼抽象不容易瞭解。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年7月21日 上午 08:43
  • 只是為了方便說明, 會將Application啟動的稱為主執行緒. 而其它再產生的稱為次執行緒或子執行緒.
    想要多瞭解的話, 就要多爬文, MSDN 文件庫有相當多關於執行緒的文章. 我也是看那個學的.

    補充說明:
    我上次不是有貼這個連結? [建立執行緒並在啟動時間傳遞資料 ]
    裡面不是有提到下面這段話?你這樣的問法, 讓我感覺我幫你找這些資料好像是浪費時間.
    ===========================================================
    將資料傳遞給執行緒以及擷取來自執行緒的資料

    在 .NET Framework 2.0 版中,當您呼叫 Thread.Start 方法多載時,ParameterizedThreadStart 委派可讓您輕鬆地將含有資料的物件傳遞給執行緒。如需程式碼範例,請參閱 ParameterizedThreadStart

    使用 ParameterizedThreadStart 委派並不是傳遞資料的型別安全方式,因為 Thread. Start 方法多載會接受任何物件。替代方案是在 Helper 類別中封裝執行緒程序和資料,並使用 ThreadStart 委派來執行執行緒程序。下列兩個程式碼範例將會示範這項技術。

    這些委派都不具有傳回值,因為沒有地方可供傳回來自非同步呼叫的資料若要擷取執行緒方法的結果,可以依照第二個程式碼範例所示,使用回呼 (Callback) 方法。

    ==========================================================
    你看到粗體這部份, 就可以去爬文看一下有關於CallBack的說明, 例如:
    [事件和回呼 ]
    [回呼函式 ]
    [HOW TO:實作回呼函式 ]
    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重

    不會浪費時間的~因為所有回覆的前輩 所找的或解釋的都對我很有幫助 ~ 只能說小弟理解力比較差~雖然有對C#看過一些書自我學習 但是實際經驗比較少~ 對一些沒用過的寫法比較陌生 ~ 和MSDN內的寫法有些也不太能理解 ~ 可能前輩們所貼的東西 ~ 我不是剛好能看到前輩們想要我看的內容 ~ 但是我都有認真看過和學習的 ~ 所以不會白浪費前輩們的時間  ~ 如果有重複問了一些類似的問題 ~ 讓前輩們有覺得浪費時間的感覺 ~ 在此至上萬分歉意
    不過我是真的很想學好程式設計 ~  
    2009年7月21日 上午 10:11
  • 抱歉~還是要在問一下~因為真的不理解他的運作~ 這是範例 ~ 跟 Bill大的差不多
    不是很清楚有鍵號的那幾行是怎麼用的?


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    namespace ConsoleApplication11
    {
        public class ThreadWithState
        {       
            private string boilerplate;
            private int value;
            private ExampleCallback callback;

            public ThreadWithState(string text, int number, ExampleCallback callbackDelegate)  
            {
                boilerplate = text;
                value = number;
                callback = callbackDelegate;
            }

            public void ThreadProc()
            {
                Console.WriteLine(boilerplate, value);
                if (callback != null)
                    callback(1);     //<- 這裡為什麼傳入數值能控制顯示數值
            }
        }

        public delegate void ExampleCallback(int lineCount);

        public class Example
        {
            public static void Main()
            {       
                ThreadWithState tws = new ThreadWithState("This report displays the number {0}.", 42, new ExampleCallback(ResultCallback));

                Thread t = new Thread(new ThreadStart(tws.ThreadProc));
                t.Start();
                Console.WriteLine("Main thread does some work, then waits.");
                t.Join();
                Console.WriteLine("Independent task has completed; main thread ends.");

                Console.Read();
            }

            public static void ResultCallback(int lineCount)     //<- 他需要傳入一個int 是在哪傳入的為什麼能用上面的鍵號那行控制
            {
                Console.WriteLine("Independent task printed {0} lines.", lineCount);
            }
        }
    }

    2009年7月22日 上午 08:29
  • 1. 定義委派 public delegate void ExampleCallback(int lineCount);
    2. 定義類別中的私有委派攔位 private ExampleCallback callback;
    3. 定義ThreadWithState建構函式,會傳入委派 public ThreadWithState(string text, int number, ExampleCallback callbackDelegate) 
    並將傳入的委派指派給callback
      callback = callbackDelegate;
    4.      呼叫委派  callback(1);    
    5. 註冊委派要呼叫的Function ->  ThreadWithState tws = new ThreadWithState("This report displays the number {0}.", 42, new ExampleCallback(ResultCallback));

           public static void ResultCallback(int lineCount)   
            {
                Console.WriteLine("Independent task printed {0} lines.", lineCount);
            }
    步驟五就是為了把   public static void ResultCallback(int lineCount)    傳給  public ThreadWithState
    所以 callback(1)=ResultCallback(1)



    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    • 已標示為解答 Q楓仔Q 2009年7月23日 上午 03:14
    2009年7月22日 上午 08:51
    版主


  • 1. 定義委派public delegate void ExampleCallback(int lineCount);  是不是只要傳的參數型態相同就能傳?

        就是假如我有一個方法 show(int x) 也能傳嗎?


    2. 比較有問題的是ThreadWithState tws = new ThreadWithState("This report displays the number {0}.", 42, new ExampleCallback(ResultCallback));

        ExampleCallback(ResultCallback) 符合 ExampleCallback callbackDelegate 所要傳入的型態, callbackDelegate 的資料用來指定callback , 

        callback 代表的是 ExampleCallback(int lineCount); 那 ResultCallback(int lineCount) 和 callback(int lineCount) 的關系是? 

       就是第五步驟的部分有點卡住了 ..   

       我從ThreadWithState tws = new ThreadWithState("This report displays the number {0}.", 42, new ExampleCallback(ResultCallback)); 所傳入的東西

       道著追尋回去,但是追到callback(1) 和 ResultCallback(1) 的關聯就有點卡住了...
    2009年7月23日 上午 03:14
  • http://www.dotblogs.com.tw/yc421206/archive/2009/02/13/7141.aspx
    http://www.dotblogs.com.tw/yc421206/archive/2009/02/16/7206.aspx
    參考~
    2009年7月23日 上午 07:09
  • 教你一個很牛的方法, 你把程式碼列印出來, 拿著鉛筆, 用你的頭腦去跑這個程式 , 鉛筆用來畫程序的線 (像我是亂塗鴉, 畫個醜醜的線加個箭頭) , 你重覆這動作幾次, 就大概會懂了 , 有時候光靠電腦跑結果會有點迷糊, 就把你的手和腦當作CLR來跑跑程式, 比較能親身感受.
    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    2009年7月23日 下午 02:58
    版主