王朝网络
分享
 
 
 

WIN32下DELPHI中的多线程【变量存储】(三)

王朝delphi·作者佚名  2006-12-12
宽屏版  字体: |||超大  

线程中的变量

由于每个线程都代表了一个不同的执行路径,因此,最好有一种只限于一个线程内部使用的数据,

要实现上述目的有以下几种方式:

1、局部变量(基于栈),很简单,在你的线程函数中你定义的变量既是如此。由于每个线程都在各自的栈中,各个线程将都有一套局部变量的副本,这样,就不会相互影响。对于那些只在过程或函数的生存期有意义的变量,应当把它们声明为局部变量。

2、存储在线程对象中。还记得CreateThread函数中的lpParameter参数吗,它可以接受一个无类型的指针。结合本文第一章的内容,你应该还记得,它被存储在线程内核对象的上下文结构中,你可以通过CONTEXT结构中的CONTEXT_INTEGER部分的ebx来读取它的地址。

下面是一段示例代码,用来演示读取CONTEXT结构,这段代码一般用不到,但它可以说明CrateThread函数中的lpParameter被存储的位置

...{

作者:wudi_1982

联系方式:wudi_1982@hotmail.com

转载请著名出处,本代码为演示代码,只贴出了一些关键部分

}

type

//传递给线程函数的结构和指针的声明

Tinfo = record

count : integer;

x : integer;

y : integer;

end;

Pinfo= ^Tinfo;

var

MyThreadHad : THandle;//一个全局变量,用来保存线程的句柄

//线程函数

function MyThread(info : Pointer):DWORD; stdcall;

var

i : integer;

begin

//根据传递来信息决定在窗口的那个位置输出什么信息

for i := 0 to Pinfo(info)^.count-1 do

Form1.Image1.Canvas.TextOut(Pinfo(info)^.x,Pinfo(info)^.y,inttostr(i));

//FreeMem(info);

Result := 0;

end;

//创建一个线程

procedure TForm1.Button4Click(Sender: TObject);

var

ppi : Pinfo;

MyThreadId : DWORD;

begin

//分配空间并赋初值

ppi :=AllocMem(sizeof(tinfo));

ppi^.count := 1000000;

ppi^.x := 10;

ppi^.y := 10;

//创建

MyThreadHad := CreateThread(nil,0,@MyThread,ppi,CREATE_SUSPENDED,MyThreadId);

//在窗体上显示线程函数的地址和传递给它的参数的地址

labThreadAddr.Caption := inttostr( integer(@MyThread));

labThreadPvparam.Caption := inttostr(integer(ppi));

end;

//读取CONTEXT结构,注意CONTEXT结构是和CPU有关的,我这里测试时,工作在intel的CPU上

procedure TForm1.btnRContextClick(Sender: TObject);

var

con : _CONTEXT;

begin

//初始化结构

con.ContextFlags := CONTEXT_FULL;

//读取

GetThreadContext(MyThreadHad,con);

//显示在窗体的listbox上

with lbxContextInfo.Items do

begin

// Clear;

Add('------------CONTEXT--------------');

Add('');

Add('CONTEXT_DEBUG_REGISTERS-----');

Add('dr0:'+#9+IntToStr(con.Dr0));

Add('dr1:'+#9+IntToStr(con.Dr1));

Add('dr2:'+#9+IntToStr(con.Dr2));

Add('dr3:'+#9+IntToStr(con.Dr3));

Add('dr6:'+#9+IntToStr(con.Dr6));

Add('dr7:'+#9+IntToStr(con.Dr7));

add('CONTEXT_SEGMENTS---------');

Add('segGs:'+#9+inttostr(con.SegGs));

Add('segFs:'+#9+inttostr(con.Segfs));

Add('segEs:'+#9+inttostr(con.Seges));

Add('segDs:'+#9+inttostr(con.Segds));

Add('CONTEXT_INTEGER.---------');

Add('edi: '+#9+IntToStr(con.Edi));

Add('esi: '+#9+IntToStr(con.Esi));

Add('ebx: '+#9+IntToStr(con.Ebx));

Add('edx: '+#9+IntToStr(con.Edx));

Add('ecx: '+#9+IntToStr(con.Ecx));

Add('eax: '+#9+IntToStr(con.Eax));

Add('CONTEXT_CONTROL----------');

Add('Ebp: '+#9+IntToStr(con.Ebp));

Add('Eip: '+#9+IntToStr(con.Eip));

Add('segcs: '+#9+IntToStr(con.SegCs));

Add('EFlags: '+#9+IntToStr(con.EFlags));

Add('Esp: '+#9+IntToStr(con.Esp));

Add('SegSs: '+#9+IntToStr(con.SegSs));

end;

end;

把上面代码整理之后,添加到你的程序中,你可以发现(如果也是intel的CPU),那么你可以从Eax寄存器读取到线程函数的地址,从Ebx中读取到传递给线程函数的参数地址。

在DELPHI中的TThread对象的构造函数中,你可以看到这段代码

FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);

再观察BeginThread的实现,你会发现TThread的调用CreateThread时,将Pointer(Self),也就是TThread对象本身当作线程函数的参数传递过去,换言之,你在TThread的派生类中定义的变量,对于一个线程而言,将存储在这个线程单独的堆栈中,而它在堆栈的地址存储在线程的上下文结构中。

可以做一个简单的试验,将一个线程生成多次,你可以发现存储在线程对象内部的变量将互不影响。

说到这里,必须谈论一个问题,效率的问题,我在一本书上曾经看到过这样一段话“由于访问线程对象中的数据比访问线程局部变量要快10倍,因此,你应当尽可能地把线程专用的信息保存在线程对象中。”对此,我一直没有特别理解。如果一定要相信这句话,那我会这么理解,就是存储在线程对象中的变量因为上下文结构记录了它的地址等原因,所以它更快。尽信书不如无书,我还在思考,不过好在这种速度的影响对于通常的使用而言影响不大。

3、在DELPHI中,用Object Pascal的关键字threadvar来声明变量,以利用操作系统级的线程局部存储。

在前面我们了解到:虽然对于局部变量,在每个线程中都一个副本,然而应用程序的全局变量是被所有线程所共享的。当多个线程对这个全局变量进行访问时,将可能出现很多未知的问题,Win32提供了一种称为线程局部存储的方式,它能使你在第一个运行的线程中创建一个全局变量的拷贝。Delphi利用关键字threadvar封装此功能。在threadvar关键字下你可以声明任何局部存储的变量。

4、全局变量,多线程最让人头疼的地方就是全局变量了,好的同步方式将决定你高效、安全的访问全局变量,虽然上述的threadvar是解决全局变量线程局部存储的一个办法,但在我实际的编码工作中,几乎很少用它,它的局限性太多。多线程访问全局变量的方法将在下一文中详细描述。

注:转载请著名出处,谢谢!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有