我说的并不是:丢个函数给子线程调用的问题。
而是,子线程如何通知主线程调用某函数?
描述:有主线程A,开了一个子线程B。现在有一个函数 F ,需要在B执行到某个时刻时,通知A线程执行F。
实例说明:.net中的 windows form窗体是只能由窗体线程来调用更改的。如果在窗体中开出一个线程执行一段计算。在计算完成后,需要将结果显示到窗体上。在这样的应该用中,子线程是以什么样的原理来通知窗体线程的显示计算结果的?
我要的是 ”原理“,请大大脱离 语言本身来 回答这个问题。
不要告诉我说 有个什么什么组件或者类能实现。
这个问题我放上所有的园豆。先感谢各位。另外:如果回答也不了,也希望能提供想要的资料和文章,结贴前也会给豆豆。
首先,当主线程创建的时候,会建立一个Looper对象,
然后子线程执行到需要主线程调用某方法的时候,会将Message加入到一个MessageQueue队列,
Looper对象所属的线程在Looper.Loop方法中循环执行从MessageQueue队列读取Message对象
当读取到Message的时候,就会调用主线程中的相应方法
http://www.cnblogs.com/fish-li/archive/2011/10/23/2222013.html
上面页面中,有个详细的示例。
讲的是在一些异步操作,刚才示例本身是用WinForm演示的。异步本身就是多线程环境,示例中就演示你想要的效果。
示例中方法使用的原理:由同步上下文将调用切换到控件创建的线程,也就是最终转交给主线程,最后由它来显示结果。
其实在WinForm中还有另一种Win32的方法,那就是SendMessage,这种方法可以绕开线程问题,它直接使用窗口的消息队列。
以一个实例来说明这个原理:一个winform窗体,有一个计算按钮,点击计算按钮后,后台开启线程进行很复杂很耗时的计算,但是却不影响用户在主线程(其实就是UI线程)的输入(即窗体不能卡死,用户依然能输入/点击并得到响应)。
class UIThread
{
ConcurrentQueue<Message> Queue;
public void Start()
{
while(true) //while(Application.IsRunning)
{
var msg = GetAMessageFromQueue();
HandleMessage(msg);
}
}
}
//而你后台新线程里所谓的control.Invoke方法(我们常说的,不能跨线程改变控件,要用Invoke),其实就是类似于这样:
//假设我要在另外一个线程里把textbox1.Text改了
uithread.Queue.Enqueue("麻烦把textbox1的text改了!")
再某一个时刻,UIThread的Queue可能看起来是这样的:
[textbox2的Text变成"hello", button1点击了, progressbar的进度调到41%, button1不可点了]
无论是用户操作UI,还是后台代码操作UI,还是其他线程操作UI,本质都是把“消息”放入一个队列,然后UI线程按照一定的策略去取,并执行(最简单的就是先来先执行,FIFO)。所有负责展示的代码都由一个UI线程去完成,这个线程里有个运行时的死循环,不断从队列里拿东西并直观反映到屏幕上。
将主线程挂起,直到子线程去唤醒这个主线程,主线程才继续执行方法,就是在F方法中有一个唤醒主线程的操作。
将子线程包成一个类 C1 并在其中定义一个事件
public delegate void ShowResultHandler(double r);
public event ShowResultHandler ShowResult ;
在类C1的运算结果处
if( ShowResult !=null)
ShowResult (xx) ; //xx 是计算的结果
在主线程 中注册事件
C1 c =new C1() ;
Thread t =new Thread(c1.mainfun,.....) ;
c.ShowResult += C1.ShowResultHandler (GetResult);
void GetResult(double r)
{
//当子线程计算完成后,就会触发事件 ,可以此显示结果,注意跨线程显示要使用invoke包起来
}
....
不知道“原理”该怎么理解,就说下我认为的吧
线程这个东西,存在的意义就是影响系统内核分配CPU时间片段,开启一个线程,就是告诉内核请分配CPU时间给我,具体内核怎么分,是操作系统的事,程序干预不了,根据你的线程级别,也许马上分给你,也许过会再分。
那么重点就清楚了,两个线程不能直接互相影响。内存这些资源没问题,有权限谁写都行,但CPU时间片段只能系统内核调度,我们都是抢占式操作系统。
回到你说的,线程B执行到了某个时刻,主线程(或窗口线程)A是不知道的,怎么办呢,大家都做法是,在A中做个循环,等待B的一个通知。这里注意,A在循环等待中也是要花费CPU时间的,而B的通知,只是个标识,并不能影响内核对A的CPU时间分配,而是当A收到这个通知,则会把分配给自己的CPU时间 用于函数F的计算。整个过程中,A使用着分配给自己的CPU时间,B也使用着分配给自己的。
这样吧,不知道你问得是不是这个
你要把this指针传进去
static函数不能使用外部的东西
hThread=CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)Action1,
(LPVOID)this,
0,
NULL);
static DWORD Scrap1(LPVOID lParam);
DWORD Action1(LPVOID lParam)
{
CTestDlg * _this = (CTestDlg *)lParam;
_this->Scrap();
return 0;
}