关于C#代表的问题

本文关键字:问题 关于 | 更新日期: 2023-09-27 17:59:04

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() 

什么都不打印?

关于C#代表的问题

您的程序可能会退出,导致线程终止(或在线程有时间启动之前(就像显式创建线程一样,也需要显式等待线程完成

您需要使用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();

您的代码对我来说是有效的,尽管我不得不充实文章中遗漏的部分。除非我做了与你截然不同的事情,否则问题一定出在其他地方。

下面的代码在控制台应用程序中运行良好:我看到"Test"以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(创建的线程可能永远不会在程序终止之前执行。

您需要等待,以便有足够的时间来构造(昂贵的(新线程并安排执行。"多线程"answers"并发"并不意味着瞬时。它们意味着每单位时间的工作量要比大量工作的平均工作量多。

要降低后台线程操作的成本,请考虑用ThreadPool.QueueUserWorkItem()替换new Thread(),以利用现有的工作池线程。这将节省时间和内存。

此外,请仔细考虑将工作推到后台线程中是否真的值得额外的线程开销。如果写入日志可能会阻塞文件I/O或网络I/O,那么在后台线程中执行可能会很困难,但也有其他技术可以在不需要创建新线程的情况下执行异步I/O。

还要考虑频率。与其每次想要输出几个字符的文本都启动一个新线程,不如启动一个监听队列并在大部分时间睡眠的后台线程,并让主线程将消息推送到队列中。