开发者

A Question About C# Delegates

开发者 https://www.devze.com 2023-03-12 06:06 出处:网络
class ClassA { public delegate void WriteLog(string msg); private WriteLog m_WriteLogDelegate; public ClassA(WriteLog writelog)
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 开发者_JAVA技巧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);
            }
        }
}

Why the following code

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

prints "msg" and this one

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

doesn't print anything?


Your program likely exits causing the thread to be terminated (or before the thread has time to start). Just as you explicitly created a thread, you need to explicitly wait for the thread to complete!

You need to use Thread.Join or some other method to keep the main program waiting for the thread to complete.

One possible option, using Thread.Join:

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

...

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

Another option, using a 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();
    }

Then your code which call b.test2():

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


Your code is working for me, although I had to flesh out the parts that were omitted from the post. Unless I did something drastically different from what you're doing, the problem must be somewhere else.

The code below works fine in a console application: I see "Test" printed at 1-second intervals.

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


In what context is b.test1() being called? If it's a console app and the next thing after the call to b.test1() is to terminate the program, then the thread created by b.test1() will probably never execute before the program terminates.

You need to wait to allow enough time for the new thread to be constructed (expensive) and scheduled for execution. "Multithreaded" and "concurrent" do not mean instantaneous. They mean more work per unit of time averaged over a lot of work.

To reduce the cost of the background thread operation, consider replacing your new Thread() with ThreadPool.QueueUserWorkItem() to make use of an existing worker pool thread. This will save time and memory.

Also, consider carefully whether the work you're pushing off into the background thread is really worth the extra threading overhead. If writing to the log may potentially block on file I/O or network I/O, then doing it in a background thread might be warrented, but there are also other techniques to perform an asynchronous I/O without you needing to create a new thread.

Also consider frequency. It would be better to spin up a background thread that listens to a queue and sleeps most of the time, and have the main thread push messages into the queue, than to spin up a new thread every time you want to output a few chars of text.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号