200分 --->多线程调用同一个函数的安全问题<--- 200分

flyinwuhan 2004-04-22 02:25:41
我写了这样一个函数:
function Test( s:string ):Pointer;
var
ary : array [0..255] of char;
begin
strpcopy( ary, s );
result := @ary[0];
end;

问题是,如果多个线程同时调用函数Test的话会不回发生冲突?
我做的实验,在每一个线程中调用Test函数,所有线程调用Test函数的返回值是固定的,也就是说多个线程访问的是同一片内存。

“这个问题好象是有些让人迷惑。因为我没做过具体的测试。如果是线程局部变量的话,他们都有各自的副本,是互不干扰的。但现在是函数内变量,(这个函数应该看做是全局变量),而不是线程内变量。从汇编级来看的话。是不是可以这样来看????
每个线程都是 call test。test是同一个,只不过它被多个线程调用,只有一个TEST存在的话,那么 ARY 肯定也就是 分配在一个固定的地方。基于这个想法,ARY应该是分配在同一个栈空间上。不知道对不对。我自己也很怀疑。”
...全文
657 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
kingrain213 2010-06-03
  • 打赏
  • 举报
回复
不太明白
flyinwuhan 2004-04-22
  • 打赏
  • 举报
回复
呵呵,高手很多,这个帖子分太少!
请 ttch(最近比较烦(工作没找到)) 和 SydPink(希望不再敲键盘!) 到这里领分:
http://expert.csdn.net/Expert/topic/2984/2984616.xml?temp=.5994379
其实那个帖子问的就是这个问题,代码太长了没有人看啊,我只好分开来问。
二位只要UP一下上面的帖子即可,我等着结帖呢!快!
flyinwuhan 2004-04-22
  • 打赏
  • 举报
回复
试验代码的主要问题就是Execute方法只运行了一次,无论我先后启动多少个线程而在同一时间却只有一个线程在运行(其他的线程早已Terminated)

感谢大家!
flyinwuhan 2004-04-22
  • 打赏
  • 举报
回复
呵呵,实验源代码如下:

//线程部分
unit Unit2;

interface

uses
Classes, SysUtils;

type
YThread = class(TThread)
private
{ Private declarations }
FText : string;
protected
procedure Execute; override;
public
procedure UpdateCaption;
end;

implementation

uses Unit1;

procedure YThread.UpdateCaption;
begin
Form1.ListBox1.Items.Add( FText );
end;

procedure YThread.Execute;
var
p : Pointer;
begin
while not Terminated do
begin
p := Test( Form1.Text );
FText := StrPas( p ) + '___' + IntToStr(Integer(p));
Synchronize( UpdateCaption );
Sleep(3000);
end;
end;

end.

正如ehom(?!) 老大所说,“地址不会相同”

我原来试验是相同的。。。。。。为什么?因为我原来的代码是这样的:
procedure YThread.Execute;
var
p : Pointer;
begin
p := Test( Form1.Text );
FText := StrPas( p ) + '___' + IntToStr(Integer(@p));
Synchronize( UpdateCaption );
end;

ehom 2004-04-22
  • 打赏
  • 举报
回复
地址不会相同,贴你的实验代码~~~

根本点上一帖就说完了,这又不是堆上动态分配,不会导致异常.
ImFool 2004-04-22
  • 打赏
  • 举报
回复
嗨,大家为什么不说根本点(呵呵,我也没说):函数结束时ary已经释放了!!!!返回的是无效指针。
laihaiming 2004-04-22
  • 打赏
  • 举报
回复
up
flyinwuhan 2004-04-22
  • 打赏
  • 举报
回复
>>不光返回变量值,把变量所在地址也返回来看看就知道了。值相同,而且地址也相同,就证明多个线程的多次运行其实是在写同一个地方

result := @ary[0];返回的不就是地址吗?一直是相同的。

同意ehom(?!) 的说法,但是我不得不这么办,因为我不能动态分配内存。。。
至于原因我会再发一个帖子
ehom 2004-04-22
  • 打赏
  • 举报
回复
在切换线程序的时候,将保存当前的寄存器的内容到CONTEXT结构,在该线程恢复运行时,恢复寄存器状态.所以栈对于多线程来说自然是安全的.每个线程执行时栈内存一样?

栈由栈基址(EBP寄存器),栈顶(ESP寄存器)记录状态.所谓的释放栈内数据只是改变ESP寄存器,也就是移动栈顶.你上面返回的只是一个指针,它指向的数据不会因为移动栈顶而改变,但是这样写程序是非常糟糕的,这个返回的地址中的数据也是不安全的.

>>我做的实验,在每一个线程中调用Test函数,所有线程调用Test函数的返回值是固定的,也就是说多个线程访问的是同一片内存。

我觉得你的实验有问题,应该是不同的~~~
ImFool 2004-04-22
  • 打赏
  • 举报
回复
这个函数本身有问题,跟是否多线程毫无关系。
ttch 2004-04-22
  • 打赏
  • 举报
回复
先跟一下 回去做下实验再把结果贴上

================================

在编译器角度上看这个问题,在一进程内有不同的空间,在LOAD一EXE文件的时候,如果有多进程操作系统会为每个线程分配一个子空间,这个空间是相对独立的.

而函数的参数在栈中 当每个线程使用这个函数的时候会用浅拷贝他的指针,然后调用指针实现函数调用.但如果涉及到互斥的问题,他的参数栈都不在一个位置,也就是栈不同,而TEST函数中的临时变量相同.然后调用的时候会有退栈和进栈的问题.

相对来说,这样不会有资源冲突的问题

对于函数的临时变量 我还是那意思,他永远是浅拷贝.多个指针指向同一个空间.

你可以看看RTL中的实现,对于多线程,他的ESP会有POP和PUSH的功能.
SydPink 2004-04-22
  • 打赏
  • 举报
回复
我现在还没有做测试,,楼主可以继续做一下测试。不光返回变量值,把变量所在地址也返回来看看就知道了。值相同,而且地址也相同,就证明多个线程的多次运行其实是在写同一个地方。
alphax 2004-04-22
  • 打赏
  • 举报
回复
兄弟们,明天再弄吧,


回家吃饭去咯
alphax 2004-04-22
  • 打赏
  • 举报
回复
2 键盘

>>但是现在这个变量A是 在一个公用函数内部分配的。如果楼主的测试没有错的话,
>>么 ARY 肯定也就是 分配在一个固定的地方。

不一定的,这要是运行时stack的具体情况
楼主的测试肯定有问题

>>基于这个想法,
>>ARY应该是分配在同一个栈空间上

对同一个thread,每次调用,都在thread私有的stack上,
但是即使对同一个thread,在不同环境下调用函数,ary的地址就不同了

已经说了,在函数体外ary的地址是没有意义的,
ttch 2004-04-22
  • 打赏
  • 举报
回复
先收了 回头再看看 :) 函数有自动退栈和自动进栈功能,这里是实现多线程的关键

还有就是,编译器编译静态栈部分会自动跟踪那些没有失效的变量,直到变量失效为止.

以上是我说的醉话 回头仔细看过帖子再回
路人丁 2004-04-22
  • 打赏
  • 举报
回复
function Test( s:string ):Pointer;
var
ary : array [0..255] of char;
begin
strpcopy( ary, s );
result := @ary[0];
end;
1、你的函数有问题,临时变量地址返回自然是会遇到麻烦,因为你的临时变量生存期在函数调用结束时就到期了。
你有可能得到正确的结果是因为虽然临时变量被释放了,但是该临时变量使用的内存空间不一定被覆盖,因此可能得到正确的结果。
2、至于你得到一个固定值可能是因为前面所说的错误造成的。不能说“同一个函数不同调用申请的是不同的空间”因为如果你的第一次调用结束了第二次调用时可能利用了第一次调用的空间,因为第一次所使用的空间已经释放了。
3、解决这个问题可以自己申请内存空间,这样只要你不去释放他它是不会消失的。
SydPink 2004-04-22
  • 打赏
  • 举报
回复
alphax(多喝了三五杯) ( ) 信誉:130 2004-04-22 16:55:00 得分:0


看了,

>>是不是不同的线程调用这个函数时,ary分配在不同的栈空间上呢?

对,因为每个thread的栈是不同的

//////////////////////
thread的栈是不同的
这完全正确,如果有一个变量A是属于线程内局部变量的话。他们的地址和所在栈是完全不同的。
但是现在这个变量A是 在一个公用函数内部分配的。如果楼主的测试没有错的话,
么 ARY 肯定也就是 分配在一个固定的地方。基于这个想法,ARY应该是分配在同一个栈空间上
WGYKING 2004-04-22
  • 打赏
  • 举报
回复
关注
alphax 2004-04-22
  • 打赏
  • 举报
回复
它们的语义是一样的

function ReturnPtr: Pointer;
var
VarOnStack: array[0..9] of Byte;
begin
Result := @VarOnStack[0];
end;

Shiyl 2004-04-22
  • 打赏
  • 举报
回复
不如把
VarOnStack: array[0..9] of Byte;
定成全局变量
可能能够解决问题的说
加载更多回复(15)

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧