首页 新闻 会员 周边

请教:子线程回调主线程函数的原理

0
悬赏园豆:200 [已解决问题] 解决于 2013-09-08 20:07

我说的并不是:丢个函数给子线程调用的问题。

而是,子线程如何通知主线程调用某函数?

描述:有主线程A,开了一个子线程B。现在有一个函数 F ,需要在B执行到某个时刻时,通知A线程执行F。

实例说明:.net中的 windows form窗体是只能由窗体线程来调用更改的。如果在窗体中开出一个线程执行一段计算。在计算完成后,需要将结果显示到窗体上。在这样的应该用中,子线程是以什么样的原理来通知窗体线程的显示计算结果的?

我要的是 ”原理“,请大大脱离 语言本身来 回答这个问题。

不要告诉我说 有个什么什么组件或者类能实现。

这个问题我放上所有的园豆。先感谢各位。另外:如果回答也不了,也希望能提供想要的资料和文章,结贴前也会给豆豆。

红色壁虎的主页 红色壁虎 | 菜鸟二级 | 园豆:202
提问于:2012-01-14 17:08
< >
分享
最佳答案
0

首先,当主线程创建的时候,会建立一个Looper对象,

然后子线程执行到需要主线程调用某方法的时候,会将Message加入到一个MessageQueue队列,

Looper对象所属的线程在Looper.Loop方法中循环执行从MessageQueue队列读取Message对象

当读取到Message的时候,就会调用主线程中的相应方法

收获园豆:30
xiezhengcai | 初学一级 |园豆:5 | 2012-01-15 21:29
其他回答(6)
0

http://www.cnblogs.com/fish-li/archive/2011/10/23/2222013.html

上面页面中,有个详细的示例。

讲的是在一些异步操作,刚才示例本身是用WinForm演示的。异步本身就是多线程环境,示例中就演示你想要的效果。

示例中方法使用的原理:由同步上下文将调用切换到控件创建的线程,也就是最终转交给主线程,最后由它来显示结果。

其实在WinForm中还有另一种Win32的方法,那就是SendMessage,这种方法可以绕开线程问题,它直接使用窗口的消息队列。

收获园豆:30
Fish Li | 园豆:397 (菜鸟二级) | 2012-01-14 22:19
0

以一个实例来说明这个原理:一个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线程去完成,这个线程里有个运行时的死循环,不断从队列里拿东西并直观反映到屏幕上。

收获园豆:30
水牛刀刀 | 园豆:6350 (大侠五级) | 2012-01-16 10:33
2

将主线程挂起,直到子线程去唤醒这个主线程,主线程才继续执行方法,就是在F方法中有一个唤醒主线程的操作。

收获园豆:30
az235 | 园豆:8483 (大侠五级) | 2012-01-16 10:35
0

将子线程包成一个类 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包起来
}

....

收获园豆:30
杨孔来 | 园豆:262 (菜鸟二级) | 2012-01-17 14:49
0

不知道“原理”该怎么理解,就说下我认为的吧

线程这个东西,存在的意义就是影响系统内核分配CPU时间片段,开启一个线程,就是告诉内核请分配CPU时间给我,具体内核怎么分,是操作系统的事,程序干预不了,根据你的线程级别,也许马上分给你,也许过会再分。

那么重点就清楚了,两个线程不能直接互相影响。内存这些资源没问题,有权限谁写都行,但CPU时间片段只能系统内核调度,我们都是抢占式操作系统。

回到你说的,线程B执行到了某个时刻,主线程(或窗口线程)A是不知道的,怎么办呢,大家都做法是,在A中做个循环,等待B的一个通知。这里注意,A在循环等待中也是要花费CPU时间的,而B的通知,只是个标识,并不能影响内核对A的CPU时间分配,而是当A收到这个通知,则会把分配给自己的CPU时间 用于函数F的计算。整个过程中,A使用着分配给自己的CPU时间,B也使用着分配给自己的。

这样吧,不知道你问得是不是这个

收获园豆:30
bincurd | 园豆:235 (菜鸟二级) | 2012-01-19 12:21
0

你要把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; 

收获园豆:20
翔宇2013 | 园豆:222 (菜鸟二级) | 2013-09-06 13:37
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册