簡體   English   中英

關於 C# 代表的問題

[英]A Question About C# Delegates

class ClassA
{
public delegate void WriteLog(string msg);
private WriteLog m_WriteLogDelegate;

public ClassA(WriteLog writelog)
{
    m_WriteLogDelegate =  writelog;
    Thread thread = new Thread(new ThreadStart(Search));
    thread.Start();
}

public void Search()
{
    /* ... */
    m_WriteLogDelegate("msg");
    /* ... */
}

}

class classB
{
        private ClassA m_classA;

        protected void WriteLogCallBack(string msg)
        {
            // prints msg
            /* ... */
        }

        public classB()
        {
            m_classA = new ClassA(new WriteLog(WriteLogCallBack));
        }

        public void test1()
        {
            Thread thread = new Thread(new ThreadStart(Run));
            thread.Start();
        }

        public void test2()
        {
            m_classA.Search();
        }

        public void Run()
        {
            while(true)
            {
                /* ... */
                m_classA.Search();
                /* ... */
                Thread.Sleep(1000);
            }
        }
}

為什么下面的代碼

ClassB b = new ClassB();
b.test2() 

打印“味精”和這個

ClassB b = new ClassB();
b.test1() 

什么都不打印?

您的程序可能退出導致線程終止(或在線程有時間啟動之前)。 就像你顯式地創建了一個線程一樣,你需要顯式地等待線程完成!

您需要使用Thread.Join或其他方法讓主程序等待線程完成。

一種可能的選擇,使用Thread.Join

public Thread test2()
{
    ...
    return thread;
}

...

b.test2().Join(); // wait for test2 to complete

另一種選擇,使用ManualResetEvent

class classB
{
    private ManualResetEvent mre = new ManualResetEvent(false);

    ...

    private void Run()
    {
        ...

        this.mre.Set(); // we completed our task
    }

    public void Wait();
    {
        this.mre.WaitOne();
    }

然后你的代碼調用b.test2()

b.test2();
b.Wait();

您的代碼對我有用,盡管我不得不充實帖子中省略的部分。 除非我做的事情與你所做的完全不同,否則問題一定出在其他地方。

下面的代碼在控制台應用程序中運行良好:我看到每隔 1 秒打印一次“測試”。

internal class ClassA
{
    public WriteLog Log { get; set; }

    public ClassA(WriteLog writeLog)
    {
        Log = writeLog;
    }

    public void Search()
    {
        Log.Print("Test");
    }
}

class classB
{
    private ClassA m_classA;

    protected void WriteLogCallBack(string msg)
    {
        // prints msg
        /* ... */
        Console.WriteLine(msg);
    }

    public classB()
    {
        m_classA = new ClassA(new WriteLog(WriteLogCallBack));
    }



    public void test1()
    {
        Thread thread = new Thread(new ThreadStart(Run));
        thread.Start();
    }

    public void test2()
    {
        m_classA.Search();
    }

    public void Run()
    {
        while (true)
        {
            /* ... */
            m_classA.Search();
            /* ... */
            Thread.Sleep(1000);
        }
    }
}

internal class WriteLog
{
    private Action<string> Callback { get; set; }

    public WriteLog(Action<string> writeLogCallBack)
    {
        Callback = writeLogCallBack;
    }

    public void Print(string msg)
    {
        Callback(msg);
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        classB b = new classB();
        b.test1();
        }
}

在什么情況下調用 b.test1()? 如果它是一個控制台應用程序並且調用 b.test1() 之后的下一件事是終止程序,那么由 b.test1() 創建的線程可能永遠不會在程序終止之前執行。

您需要等待以留出足夠的時間來構建(昂貴)並安排執行新線程。 “多線程”和“並發”並不意味着瞬時。 它們意味着每單位時間的更多工作平均超過大量工作。

要降低后台線程操作的成本,請考慮將new Thread()替換為ThreadPool.QueueUserWorkItem()以利用現有的工作池線程。 這將節省時間和 memory。

此外,請仔細考慮您正在推進到后台線程的工作是否真的值得額外的線程開銷。 如果寫入日志可能會阻塞文件 I/O 或網絡 I/O,那么在后台線程中執行此操作可能會受到警告,但也有其他技術可以執行異步 I/O,而無需創建新的線。

還要考慮頻率。 最好啟動一個后台線程來偵聽隊列並大部分時間都在休眠,並讓主線程將消息推送到隊列中,而不是每次您想要 output 幾個字符時啟動一個新線程文本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM