Вопрос о делегатах C # - PullRequest
       2

Вопрос о делегатах C #

6 голосов
/ 10 июня 2011
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() 

печатает "msg", а этот

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

ничего не печатает?

Ответы [ 3 ]

6 голосов
/ 10 июня 2011

Вероятно, ваша программа завершает работу, вызывая прерывание потока (или до того, как поток успеет начать). Так же, как вы явно создали поток, вам нужно явно дождаться его завершения!

Вам нужно использовать 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();
2 голосов
/ 10 июня 2011

Ваш код работает для меня, хотя мне пришлось конкретизировать части, которые были опущены в посте. Если я не сделал что-то радикально отличное от того, что вы делаете, проблема должна быть в другом месте.

Приведенный ниже код отлично работает в консольном приложении: я вижу «Тест», напечатанный с интервалом в 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();
        }
}
1 голос
/ 10 июня 2011

В каком контексте вызывается b.test1 ()?Если это консольное приложение и после вызова b.test1 () следующая вещь - завершить программу, то поток, созданный b.test1 (), вероятно, никогда не выполнится до завершения программы.

Вам нужно подождать, чтобы дать достаточно времени для создания нового потока (дорого) и планирования его выполнения.«Многопоточный» и «параллельный» не означают мгновенный.Они означают больше работы в единицу времени, усредненной за большую работу.

Чтобы снизить стоимость операции фонового потока, рассмотрите возможность замены new Thread() на ThreadPool.QueueUserWorkItem(), чтобы использовать существующий поток рабочего пула,Это сэкономит время и память.

Кроме того, тщательно продумайте, действительно ли работа, которую вы отправляете в фоновый поток, действительно стоит дополнительных потоков.Если запись в журнал может потенциально блокировать файловый ввод-вывод или сетевой ввод-вывод, то выполнение этого в фоновом потоке может быть оправдано, но есть и другие методы для выполнения асинхронного ввода-вывода без необходимости создания новогонить.

Также учтите частоту.Было бы лучше раскрутить фоновый поток, который слушает очередь и большую часть времени спит, и основной поток помещает сообщения в очередь, чем раскручивать новый поток каждый раз, когда вы хотите вывести несколько символовтекст.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...