c#怎么做一个多线程,让它空闲等待,直到有消息触发时再执行任务,执行完毕后继续等待

时间:2021-09-09 18:31:23
c#怎么做一个多线程,让它在那里等待,直到有消息触发(即有委托调用)时再执行任务,执行完毕后继续等待。类似VC里的CWinThread,这个就是基于消息的多线程。
我现在做的多线程都在执行完毕后立刻退出了线程。刚学习C#,请多指教啊

30 个解决方案

#1


这种情况, 如果你想手工维护这个线程, 那么考虑用AutoResetEvent, 线程做while循环, 等待event, 执行代码.

但是我更建议的是直接用ThreadPool, 让.Net来帮你管理.

#2


agree with shrinerain, just using EventWaitHandle

#3


那我主线程怎么把一些数据发给子线程。VC里可以PostMessage,然后参数里可以传数据。c#让我茫然啊

#4


那我主线程怎么把一些数据发给子线程

It's not a problem ..can using function parameter to pass a reference..



PostMessage???
 It's not a mechanism offered by programming language..how can you use it in a thread without mesage queue??

and using PostMessage, you really  pass a pointer...isn't it ..

#5


多谢haiwangstar老兄 。
在VC里是传了个指针,觉得很方便。而且有个CWinThread类,一上来就自动等待消息触发其中的事件函数,如果没有触发,线程则等待。可C#里我不知道怎么做这样一个功能,而且找不到一个合适的例子。从VC转过来真郁闷啊

#6


我的需求是主线程每隔一段时间会传一个不同的数据给子线程,子线程处理完后等待(不退出)。再隔一段时间主线程再传一个不同的数据。。。周而复始

#7


不必郁闷.绝大多数事情在.net中一定比在java中更容易,更不易出错.

等待用EventWaitHandle即可.


.net 2.0也支持带参数的线程函数.可以直接传一个对象的引用,相当于C++中传指针.
public delegate void ParameterizedThreadStart (
Object obj

可以线程函数中WaitHandle.WaitOne () ,,直到它收到信号.
可以看这个例程.

ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref12/html/T_System_Threading_EventWaitHandle.htm

#8


一定比在java中更容易

笔误,比在VC中更容易

#9


Thread+AutoResetEvent

#10


这些例子我都看过,不过没有真正理解。所以不知道怎么实现我的需求。看来不能按照VC的思维了。
VC里主线程发一个消息,子线程就有个响应的函数被调用。
在C#里是不是用WaitHandle.WaitOne   () 在子线程循环等。主线程用setEvent触发子线程继续向下走,并且设置一个 值,子线程根据该值选择相应的处理函数?
如果真是这样,基本上我做了个消息循环机制了(GetMessage()和DispatchMessage())。。。感觉有点不可能

#11


看来不能按照VC的思维了

不是什么VC的思维.你把WINDOWS机制与线程,编程语言的机制搞混淆了.实现你说的这个功能,在VC中同在.NET中的实现几乎是一模一样的,只不过,在C++中用CreateThread,CreateEvent,WaitForSingleObject,而在.net中,用了Thread,EventWaitHandle,WaitOne等. 思路完全是一模一样.所以,如果你精熟VC编程的话,那么到了.NET中只不换了一种写法,更简便了一点而已!!

至于你说的GetMessage..等等..是完全混淆了语言机制同WINDOWS窗口机制.当然,你用PostMessage也可以干活,没错. 但这不是好方法,只能说这是消息循环的一个副产品,为你所用而已. 如果你现在的开发的是一个Windows服务,你怎么办????  你也要创建一个窗口线程?? 


所以,不管是C++,还是.net,你不要老是局限在消息队列中,我们现在讨论的问题同消息队列无关..我们讨论的是线程,信号,同步,数据传递.

也不是什么不能按VC的思维..你完全可以照搬VC的思维.只所以你会这么想,是因为你的VC上的思维就是不够正确的.明白了吗...

#12


楼上有一点没搞明白, 他说的是MFC的CWinThread, 它本身可以使用消息循环的,方便之处, 就是随意可以SendMessage或PostMessage,
他交待得很清楚, 每隔一段时间会传一个不同的数据给子线程, 这对于.NET的Thread是不太方便,

while(true)
{
Event.WaitOne();
DoSomething();-----------------------------只能处理某一个相同的操作, 如果处理不同的数据,需要设计复杂的数据结构
}

#13


其实是一样的道理.

Event.WaitOne(); 
DoSomething();---------------------这里可以传递函数指针,参数的.所以这里可以执行任何操作.不会局限到一个函数里.

#14


如果楼主要线程象CWinThread那样工作, 就在线程里创建一个隐藏窗口吧, 
强调一下, winform没写过, 行不行不知道, 但WPF(net3.0)可以, 呵呵

Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
            newWindowThread.SetApartmentState(ApartmentState.STA);
            newWindowThread.IsBackground = true;
            newWindowThread.Start();

private void ThreadStartingPoint()
        {
            Window1 tempWindow = new Window1();
            tempWindow.Show();       
            System.Windows.Threading.Dispatcher.Run();
        }

#15


参考如下代码:
using System.Threading;

AutoResetEvent autoEvent = new AutoResetEvent(false);
bool closed = false;

public void DoWork()
{
    while(true)
    {
        autoEvent.WaitOne();
        if (closed) return;
        Console.WriteLine("Zswang 路过");
    }
}

private void Form1_Load(object sender, EventArgs e)
{
    Thread vThread = new Thread(new ThreadStart(DoWork));
    vThread.Start();
}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    closed = true;
    autoEvent.Set();
}

private void button1_Click(object sender, EventArgs e)
{
    autoEvent.Set();
}

#16


如果楼主是在顾虑.net中线程函数无法实现有任务则作,无任务则等待,而是一下跑到结束.

那么可参考这个的实现.实际上在C++中这个问题也是一模一样的..这个代码是C++的.道理是一模一样的.




http://blog.csdn.net/wujian53/archive/2004/11/01/162422.aspx

特别注意这段代码..


//调用线程池
 void Call(void (*pFunc)(void  *), void *pPara = NULL)
 {
  assert(pFunc);

  EnterCriticalSection(&_csWorkQueue);
  _JobQueue.push(new JobItem(pFunc, pPara));
  LeaveCriticalSection(&_csWorkQueue);

  ReleaseSemaphore(_SemaphoreCall, 1, NULL);
 }
 //调用线程池
 inline void Call(ThreadJob * p, void *pPara = NULL)
 {
  Call(CallProc, new CallProcPara(p, pPara));
 }


#17


多谢几位高手。可能我没把事情说清。不过longlijun 明白了我的苦衷啊
我先仔细看看回复,再作回复
再次谢过

#18


多谢haiwangstar 。


Event.WaitOne();   
DoSomething();---------------------这里可以传递函数指针,参数的.所以这里可以执行任何操作.不会局限到一个函数里.

能不能给一小段代码,演示 怎么传递函数指针,参数。我c#刚学,委托等等用的不灵活

#19


按照上面各位提供的线索,我的实现思路如下:

using System.Threading;

AutoResetEvent autoEvent = new AutoResetEvent(false);
bool closed = false;
static int flag;

public void DoWork()
{
    while(true)
    {
        autoEvent.WaitOne();
        if (closed) return;
        switch(flag){
           case 0:
                DoFun1();
           case 1:
                DoFun2();}
     }
}

private void Form1_Load(object sender, EventArgs e)
{
    Thread vThread = new Thread(new ThreadStart(DoWork));
    vThread.Start();
}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    closed = true;
    autoEvent.Set();
}

private void button1_Click(object sender, EventArgs e)
{
    flag=0; //根据实际情况会是不同的值。
    autoEvent.Set();
}


为了方便我省略了数据访问的线程安全。这基本上实现了消息循环和派发了。C#本身没有这样的封装?
其中我还不知道怎么把参数传过去(是每次执行button1_Click都会有不同的数据)。当然用static变量可以传,觉得会有更好的办法

#20


一直没有找到这样的代码例子

#21


up

#22


用以上方法, 需要设计较为复杂的数据结构, 另外还存在一些缺点,比如:
private   void   button1_Click(object   sender,   EventArgs   e) 

        flag=0;   //根据实际情况会是不同的值。 
        autoEvent.Set(); 
       flag=1;   //根据实际情况会是不同的值。 
        autoEvent.Set();
       flag=2;   //根据实际情况会是不同的值。 
        autoEvent.Set();


你想想, 会发生什么情况?  受线程调度影响, Thread可能只响应了一次

#23


考虑下haiwangstar的代码吧

其实, 我倒觉得创建另外一UI线程, 不失为好办法 

#24


楼主和我以前做过些一个东西类似
主线程(等待控制线程的信号,向某个工作线程发出工作信号)+控制子线程(产生事件的)+工作线程(根据控制线程来的信号开始哪个工作线程操作)
每个用类来实现,信号参数由类参传递.事件由AUTORESETEVENT来控制.

#25


autoEvent.WaitOne(); 
                if   (closed)   return; 
                switch(flag){ 
                      case   0: 
                                DoFun1(); 
                      case   1: 
                                DoFun2();} 


呵呵。你还是没有认真看,或是没看懂我给出的那段代码吧?

这样不还是死的吗??????,有限的吗?

考虑一下.net线程池,,它可以支持任何你指定的操作,只要给出一个函数指针,给出你任意给定的参数就可以。。

不是一样的道理吗

我c#刚学,委托等等用的不灵活

你会用C的函数指针,,就会用委托的。。

#26


When the CLR initializes, the thread pool has no threads in it. Internally, the thread pool maintains a queue of operation requests. When your application wants to perform an asynchronous
operation, you call some method that appends an entry into the thread pool's queue. The thread pool's code will extract entries from this queue and dispatch the entry to a thread pool thread. If there are no threads in the thread pool, a new thread will be created. Creating a thread has a performance hit associated with it (as already discussed). However, when a thread pool thread has completed its task, the thread is not destroyed; instead, the thread is returned to the thread pool, where it sits idle waiting to respond to another request. Since the thread doesn't destroy itself, there is no added performance hit.
If your application makes many requests of the thread pool, the thread pool will try to service all of the requests using just this one thread. However, if your application is queuing up several requests faster than the thread pool thread can handle them, additional threads will be created. Your application will eventually get to a point at which all of its requests can be handled by a small number of threads, so the thread pool should have no need to create a lot of threads.

#27


线程池还真没看懂,看来用这个可以解决我的问题。那就学习C#怎么用线程池:)。先去网上查查。

#28


怎么看楼主就是要像一个类似通信的线程,随便下个局域网聊天或类似的看下。

#29


写些英语一个不认识。

#30


楼主问题解决了吗?我也遇见了相同的问题,想请教下你,方便给你的QQ么?
我的QQ:349581746

#1


这种情况, 如果你想手工维护这个线程, 那么考虑用AutoResetEvent, 线程做while循环, 等待event, 执行代码.

但是我更建议的是直接用ThreadPool, 让.Net来帮你管理.

#2


agree with shrinerain, just using EventWaitHandle

#3


那我主线程怎么把一些数据发给子线程。VC里可以PostMessage,然后参数里可以传数据。c#让我茫然啊

#4


那我主线程怎么把一些数据发给子线程

It's not a problem ..can using function parameter to pass a reference..



PostMessage???
 It's not a mechanism offered by programming language..how can you use it in a thread without mesage queue??

and using PostMessage, you really  pass a pointer...isn't it ..

#5


多谢haiwangstar老兄 。
在VC里是传了个指针,觉得很方便。而且有个CWinThread类,一上来就自动等待消息触发其中的事件函数,如果没有触发,线程则等待。可C#里我不知道怎么做这样一个功能,而且找不到一个合适的例子。从VC转过来真郁闷啊

#6


我的需求是主线程每隔一段时间会传一个不同的数据给子线程,子线程处理完后等待(不退出)。再隔一段时间主线程再传一个不同的数据。。。周而复始

#7


不必郁闷.绝大多数事情在.net中一定比在java中更容易,更不易出错.

等待用EventWaitHandle即可.


.net 2.0也支持带参数的线程函数.可以直接传一个对象的引用,相当于C++中传指针.
public delegate void ParameterizedThreadStart (
Object obj

可以线程函数中WaitHandle.WaitOne () ,,直到它收到信号.
可以看这个例程.

ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref12/html/T_System_Threading_EventWaitHandle.htm

#8


一定比在java中更容易

笔误,比在VC中更容易

#9


Thread+AutoResetEvent

#10


这些例子我都看过,不过没有真正理解。所以不知道怎么实现我的需求。看来不能按照VC的思维了。
VC里主线程发一个消息,子线程就有个响应的函数被调用。
在C#里是不是用WaitHandle.WaitOne   () 在子线程循环等。主线程用setEvent触发子线程继续向下走,并且设置一个 值,子线程根据该值选择相应的处理函数?
如果真是这样,基本上我做了个消息循环机制了(GetMessage()和DispatchMessage())。。。感觉有点不可能

#11


看来不能按照VC的思维了

不是什么VC的思维.你把WINDOWS机制与线程,编程语言的机制搞混淆了.实现你说的这个功能,在VC中同在.NET中的实现几乎是一模一样的,只不过,在C++中用CreateThread,CreateEvent,WaitForSingleObject,而在.net中,用了Thread,EventWaitHandle,WaitOne等. 思路完全是一模一样.所以,如果你精熟VC编程的话,那么到了.NET中只不换了一种写法,更简便了一点而已!!

至于你说的GetMessage..等等..是完全混淆了语言机制同WINDOWS窗口机制.当然,你用PostMessage也可以干活,没错. 但这不是好方法,只能说这是消息循环的一个副产品,为你所用而已. 如果你现在的开发的是一个Windows服务,你怎么办????  你也要创建一个窗口线程?? 


所以,不管是C++,还是.net,你不要老是局限在消息队列中,我们现在讨论的问题同消息队列无关..我们讨论的是线程,信号,同步,数据传递.

也不是什么不能按VC的思维..你完全可以照搬VC的思维.只所以你会这么想,是因为你的VC上的思维就是不够正确的.明白了吗...

#12


楼上有一点没搞明白, 他说的是MFC的CWinThread, 它本身可以使用消息循环的,方便之处, 就是随意可以SendMessage或PostMessage,
他交待得很清楚, 每隔一段时间会传一个不同的数据给子线程, 这对于.NET的Thread是不太方便,

while(true)
{
Event.WaitOne();
DoSomething();-----------------------------只能处理某一个相同的操作, 如果处理不同的数据,需要设计复杂的数据结构
}

#13


其实是一样的道理.

Event.WaitOne(); 
DoSomething();---------------------这里可以传递函数指针,参数的.所以这里可以执行任何操作.不会局限到一个函数里.

#14


如果楼主要线程象CWinThread那样工作, 就在线程里创建一个隐藏窗口吧, 
强调一下, winform没写过, 行不行不知道, 但WPF(net3.0)可以, 呵呵

Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
            newWindowThread.SetApartmentState(ApartmentState.STA);
            newWindowThread.IsBackground = true;
            newWindowThread.Start();

private void ThreadStartingPoint()
        {
            Window1 tempWindow = new Window1();
            tempWindow.Show();       
            System.Windows.Threading.Dispatcher.Run();
        }

#15


参考如下代码:
using System.Threading;

AutoResetEvent autoEvent = new AutoResetEvent(false);
bool closed = false;

public void DoWork()
{
    while(true)
    {
        autoEvent.WaitOne();
        if (closed) return;
        Console.WriteLine("Zswang 路过");
    }
}

private void Form1_Load(object sender, EventArgs e)
{
    Thread vThread = new Thread(new ThreadStart(DoWork));
    vThread.Start();
}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    closed = true;
    autoEvent.Set();
}

private void button1_Click(object sender, EventArgs e)
{
    autoEvent.Set();
}

#16


如果楼主是在顾虑.net中线程函数无法实现有任务则作,无任务则等待,而是一下跑到结束.

那么可参考这个的实现.实际上在C++中这个问题也是一模一样的..这个代码是C++的.道理是一模一样的.




http://blog.csdn.net/wujian53/archive/2004/11/01/162422.aspx

特别注意这段代码..


//调用线程池
 void Call(void (*pFunc)(void  *), void *pPara = NULL)
 {
  assert(pFunc);

  EnterCriticalSection(&_csWorkQueue);
  _JobQueue.push(new JobItem(pFunc, pPara));
  LeaveCriticalSection(&_csWorkQueue);

  ReleaseSemaphore(_SemaphoreCall, 1, NULL);
 }
 //调用线程池
 inline void Call(ThreadJob * p, void *pPara = NULL)
 {
  Call(CallProc, new CallProcPara(p, pPara));
 }


#17


多谢几位高手。可能我没把事情说清。不过longlijun 明白了我的苦衷啊
我先仔细看看回复,再作回复
再次谢过

#18


多谢haiwangstar 。


Event.WaitOne();   
DoSomething();---------------------这里可以传递函数指针,参数的.所以这里可以执行任何操作.不会局限到一个函数里.

能不能给一小段代码,演示 怎么传递函数指针,参数。我c#刚学,委托等等用的不灵活

#19


按照上面各位提供的线索,我的实现思路如下:

using System.Threading;

AutoResetEvent autoEvent = new AutoResetEvent(false);
bool closed = false;
static int flag;

public void DoWork()
{
    while(true)
    {
        autoEvent.WaitOne();
        if (closed) return;
        switch(flag){
           case 0:
                DoFun1();
           case 1:
                DoFun2();}
     }
}

private void Form1_Load(object sender, EventArgs e)
{
    Thread vThread = new Thread(new ThreadStart(DoWork));
    vThread.Start();
}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    closed = true;
    autoEvent.Set();
}

private void button1_Click(object sender, EventArgs e)
{
    flag=0; //根据实际情况会是不同的值。
    autoEvent.Set();
}


为了方便我省略了数据访问的线程安全。这基本上实现了消息循环和派发了。C#本身没有这样的封装?
其中我还不知道怎么把参数传过去(是每次执行button1_Click都会有不同的数据)。当然用static变量可以传,觉得会有更好的办法

#20


一直没有找到这样的代码例子

#21


up

#22


用以上方法, 需要设计较为复杂的数据结构, 另外还存在一些缺点,比如:
private   void   button1_Click(object   sender,   EventArgs   e) 

        flag=0;   //根据实际情况会是不同的值。 
        autoEvent.Set(); 
       flag=1;   //根据实际情况会是不同的值。 
        autoEvent.Set();
       flag=2;   //根据实际情况会是不同的值。 
        autoEvent.Set();


你想想, 会发生什么情况?  受线程调度影响, Thread可能只响应了一次

#23


考虑下haiwangstar的代码吧

其实, 我倒觉得创建另外一UI线程, 不失为好办法 

#24


楼主和我以前做过些一个东西类似
主线程(等待控制线程的信号,向某个工作线程发出工作信号)+控制子线程(产生事件的)+工作线程(根据控制线程来的信号开始哪个工作线程操作)
每个用类来实现,信号参数由类参传递.事件由AUTORESETEVENT来控制.

#25


autoEvent.WaitOne(); 
                if   (closed)   return; 
                switch(flag){ 
                      case   0: 
                                DoFun1(); 
                      case   1: 
                                DoFun2();} 


呵呵。你还是没有认真看,或是没看懂我给出的那段代码吧?

这样不还是死的吗??????,有限的吗?

考虑一下.net线程池,,它可以支持任何你指定的操作,只要给出一个函数指针,给出你任意给定的参数就可以。。

不是一样的道理吗

我c#刚学,委托等等用的不灵活

你会用C的函数指针,,就会用委托的。。

#26


When the CLR initializes, the thread pool has no threads in it. Internally, the thread pool maintains a queue of operation requests. When your application wants to perform an asynchronous
operation, you call some method that appends an entry into the thread pool's queue. The thread pool's code will extract entries from this queue and dispatch the entry to a thread pool thread. If there are no threads in the thread pool, a new thread will be created. Creating a thread has a performance hit associated with it (as already discussed). However, when a thread pool thread has completed its task, the thread is not destroyed; instead, the thread is returned to the thread pool, where it sits idle waiting to respond to another request. Since the thread doesn't destroy itself, there is no added performance hit.
If your application makes many requests of the thread pool, the thread pool will try to service all of the requests using just this one thread. However, if your application is queuing up several requests faster than the thread pool thread can handle them, additional threads will be created. Your application will eventually get to a point at which all of its requests can be handled by a small number of threads, so the thread pool should have no need to create a lot of threads.

#27


线程池还真没看懂,看来用这个可以解决我的问题。那就学习C#怎么用线程池:)。先去网上查查。

#28


怎么看楼主就是要像一个类似通信的线程,随便下个局域网聊天或类似的看下。

#29


写些英语一个不认识。

#30


楼主问题解决了吗?我也遇见了相同的问题,想请教下你,方便给你的QQ么?
我的QQ:349581746