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()
什么都不打印?
答案 0 :(得分:6)
您的程序可能会退出,导致线程被终止(或者在线程有时间启动之前)。 就像你明确创建一个线程一样,你需要明确地等待线程完成!
您需要使用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 :(得分:2)
你的代码对我有用,虽然我不得不充实帖子中遗漏的部分。除非我做了与你正在做的事情截然不同的事情,否则问题必定在其他地方。
以下代码在控制台应用程序中运行良好:我看到“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();
}
}
答案 2 :(得分:1)
在什么情况下调用b.test1()?如果它是一个控制台应用程序,并且在调用b.test1()之后的下一件事就是终止程序,那么b.test1()创建的线程可能永远不会在程序终止之前执行。
您需要等待以留出足够的时间来构建(昂贵)新线程并安排执行。 “多线程”和“并发”并不意味着即时。它们意味着在大量工作中平均每单位时间的工作量。
要降低后台线程操作的成本,请考虑将new Thread()
替换为ThreadPool.QueueUserWorkItem()
以使用现有的工作池线程。这将节省时间和记忆。
另外,请仔细考虑您推送到后台线程的工作是否真的值得额外的线程开销。如果写入日志可能会阻止文件I / O或网络I / O,那么在后台线程中执行此操作可能会受到影响,但是还有其他技术可以执行异步I / O而无需创建新的线程。
还要考虑频率。最好是启动一个后台线程来监听队列并在大部分时间内休眠,并让主线程将消息推送到队列中,而不是每次要输出几个字符时启动一个新线程。文本。