代码看起来可能有点烦,不过都是些简单的code,请高手指点迷津!
线程同步类中的published方法时,Receive为inaccessible value,怎样解决?
分数可以再加.部分代码如下:...type
TForm1 = class(TForm)
...
end; //定义函数指针对象类型
TFunc = function: Integer of Object; //定义接收线程
TReceiveThread = class(TThread)
private
FFunc: TFunc;
protected
procedure SynKernel;
procedure Execute; override;
end;
//定义核心类
TKernel = class
public
Receive: TList; //接收信息缓冲
function IsCreate: Integer;
published
destructor Destroy; override;
function SynReceive: Integer; //线程同步核心类方法
end;var
Form1: TForm1;
Kernel: TKernel;
Re: TReceiveThread;implementation{$R *.dfm}{====================TReceiveThread====================}
procedure TReceiveThread.SynKernel;
begin
TMethod(FFunc).Code := TKernel.MethodAddress('SynReceive');
if Assigned(TMethod(FFunc).Code) then
if FFunc=0 then ShowMessage('not assign')
else ShowMessage('assign');
end;procedure TReceiveThread.Execute;
begin
FreeOnTerminate := True;
// while not Terminated do
Synchronize(SynKernel);
end;{====================TKernel====================}
function TKernel.SynReceive: Integer;
begin
Result := 0;
//线程同步类中的published方法时,Receive为inaccessible value,怎样解决?
if Receive=nil then Exit;
//同样,这句代码也不行
// if not Assigned(Receive) then Exit;
Result := 1;
end;constructor TKernel.Create;
begin
inherited;
Receive := TList.Create;
end;destructor TKernel.Destroy;
begin
Receive.Free;
inherited;
end;function TKernel.IsCreate: Integer;
begin
if Receive=nil then
Result := 0
else Result := 1;
end;
{====================TForm1====================}
procedure TForm1.FormCreate(Sender: TObject);
begin
Kernel := TKernel.Create; Re := TReceiveThread.Create(False);
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
Kernel.Destroy;
end;procedure TForm1.Button1Click(Sender: TObject);
begin
//这里的调用一切正常
case Kernel.IsCreate of
0: Caption := 'not assign';
1: Caption := 'assign, no data';
end;
end;
线程同步类中的published方法时,Receive为inaccessible value,怎样解决?
分数可以再加.部分代码如下:...type
TForm1 = class(TForm)
...
end; //定义函数指针对象类型
TFunc = function: Integer of Object; //定义接收线程
TReceiveThread = class(TThread)
private
FFunc: TFunc;
protected
procedure SynKernel;
procedure Execute; override;
end;
//定义核心类
TKernel = class
public
Receive: TList; //接收信息缓冲
function IsCreate: Integer;
published
destructor Destroy; override;
function SynReceive: Integer; //线程同步核心类方法
end;var
Form1: TForm1;
Kernel: TKernel;
Re: TReceiveThread;implementation{$R *.dfm}{====================TReceiveThread====================}
procedure TReceiveThread.SynKernel;
begin
TMethod(FFunc).Code := TKernel.MethodAddress('SynReceive');
if Assigned(TMethod(FFunc).Code) then
if FFunc=0 then ShowMessage('not assign')
else ShowMessage('assign');
end;procedure TReceiveThread.Execute;
begin
FreeOnTerminate := True;
// while not Terminated do
Synchronize(SynKernel);
end;{====================TKernel====================}
function TKernel.SynReceive: Integer;
begin
Result := 0;
//线程同步类中的published方法时,Receive为inaccessible value,怎样解决?
if Receive=nil then Exit;
//同样,这句代码也不行
// if not Assigned(Receive) then Exit;
Result := 1;
end;constructor TKernel.Create;
begin
inherited;
Receive := TList.Create;
end;destructor TKernel.Destroy;
begin
Receive.Free;
inherited;
end;function TKernel.IsCreate: Integer;
begin
if Receive=nil then
Result := 0
else Result := 1;
end;
{====================TForm1====================}
procedure TForm1.FormCreate(Sender: TObject);
begin
Kernel := TKernel.Create; Re := TReceiveThread.Create(False);
end;procedure TForm1.FormDestroy(Sender: TObject);
begin
Kernel.Destroy;
end;procedure TForm1.Button1Click(Sender: TObject);
begin
//这里的调用一切正常
case Kernel.IsCreate of
0: Caption := 'not assign';
1: Caption := 'assign, no data';
end;
end;
解决方案 »
- 一个问题求指教
- 关于HOOK的问题:HOOK中无法访问全局变量,如何解决?
- 蓝色之星美容美发管理系统试用版安装时,软件使用的SQL Server数据库直接就装好了,如何实现的?
- 关于checkbox
- dbgrideh设定字段时出现'无效的授权声明',如何解决(急,在线等)
- SQL语言的问题?
- 如何解决delphi6和7读取access存在问题
- 请教什么报表打印软件支持客户在程序中动台设置表格的列等信息?
- 哪位用INDY中的TCP控件做过东西,发点例子给俺吧,它自带的太简单!
- The_east_key真行,每个问题都知道,而且答案都一样,PEI,了不起啊!
- 刚才公司突然断电,再打开电脑突然发现我穿得裤衩多了一条,哈哈,庆祝!!!散分!!!
- RegisterServiceProcess 函数是在那个单元中声明的?
if FFunc = 0
进行调用时,FFunc的第二个指针(指向所属对象)为nil,那么就造成:
if Receive = nil 引用失败,因为它相当于:if Self.Receive = nil,而此时Self和Data是同一个指针而不是Kernel,因为你是通过FFunc而不是SynReceive调用。解决此问题有两个办法:
1、治标法:将
if Receive = nil 改为
if Kernel.Receive = nil
2、治本法:增加一句:
TMethod(FFunc).Data := Kernel;————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
谢谢热心的回复,实在惭愧,你的高论我还不能完全理解,class方法间的调用不指定另一class的实例handle,直接访问这个class的变量是行不通的。看来也只有引用class的实例才能行的通!
不知lxpbuaa兄是否还有更好的解决方案?如果能全部封装成一个Object当然更好!TO: FrameSniper(§绕瀑游龙§)
多谢...
如果你不明白我的意思,那么直接将:
if Receive = nil then Exit;
改为:
if Kernel.Receive = nil then Exit; 或者在:
TMethod(FFunc).Code := TKernel.MethodAddress('SynReceive');
后面加一句:
TMethod(FFunc).Data := Kernel;—————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
—————————————————————————————————
这么晚了还在,PFPF...我的意思是说不用Kernel的解决方案,因为这样封装的不好
定义TFunc为function: Integer,然后直接给FFunc赋值为SynReceive
我现在在下棋,一会回复你……—————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
—————————————————————————————————
Form1: TForm1;
Kernel: TKernel;
Re: TReceiveThread;Form1是主窗体,与用户交互
Kernel是从谁那里引申过来,而又其它类无关时,则Kernel应为那个类的private变量,否则你定义为全局变量就是一个错误的决定。
Re如Kernelprocedure TReceiveThread.SynKernel;
begin
TMethod(FFunc).Code := TKernel.MethodAddress('SynReceive');
...
end;FFunc是TReceiveThread的private,而SynReceive为TKernel成员函数,通赤MethodAddress来得到函数指针,如果SynReceive没有访问TKernel的成员变量(如访问Receive: TList),则好像没什么事,如果有,则会产生AV。概念不对。function TKernel.SynReceive: Integer;
begin
Result := 0;
//线程同步类中的published方法时,Receive为inaccessible value,怎样解决?
if Receive=nil then Exit;
//同样,这句代码也不行
// if not Assigned(Receive) then Exit;
Result := 1;
end;
你没有搞清楚成员变量在一个类实例还没产生,是没有初始化的,当然会产生AV。
因为上面那句:
TMethod(FFunc).Code := TKernel.MethodAddress('SynReceive');
就不对
TMethod(FFunc).Code := Kernel.MethodAddress('SynReceive');
or
FFunc := Kernel.SynReceive;类与类的封装很重要的一个体现就是不会使用一个莫名的全局变量,你要搞清的是每个类它的依赖关系,还有一个类实例与一个类是不一样的。
TReceiveThread = class(TThread)
private
FFunc: TFunc;
KernelObj: TObject;
KernelMethodName: ShortString;
protected
procedure SynKernel;
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean; KernelObj: TObject; KernelMethodName: ShortString); overload; //重载一个构造器
end;如下实现:
constructor TReceiveThread.Create(CreateSuspended: Boolean; KernelObj: TObject; KernelMethodName: ShortString);
begin
inherited Create(CreateSuspended);
Self.KernelObj := KernelObj;
Self.KernelMethodName := KernelMethodName;
end;
procedure TReceiveThread.SynKernel;
begin
if (KernelObj <> nil) and (KernelMethodName <> '') then
with TMethod(FFunc) do
begin
Code := KernelObj.MethodAddress(KernelMethodName);
Data := KernelObj;
if Assigned(Code) then
if FFunc = 0 then ShowMessage('not assign')
else ShowMessage('assign');
end;
end;调用:
procedure TForm1.FormCreate(Sender: TObject);
begin
Kernel := TKernel.Create;
Re := TReceiveThread.Create(False, Kernel, 'SynReceive');
end;这次行了吧?已经完全封装。
—————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
—————————————————————————————————
TKernel.MethodAddress('SynReceive');是正确的,因为方法的地址只是和类有关而与实例无关,因此TObject.MethodAddress被定义了一个类方法,不一定只有实例采用调用它。问题的关键是普通方法FFunc需要由实例调用,而它的代码里没有指定其Data(即实例),因此调用失败。至于其他的一些问题,如定义了一些不必要的全局变量,倒在其次。—————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
—————————————————————————————————
TMethod(FFunc).Code := Kernel.MethodAddress('SynReceive');
也是无济于事。
但如果直接使用:
FFunc := Kernel.SynReceive;
那么又没有体现类的封装性,因此像上面我说的那样重载线程类的构造器,应该是个比较好的解决方案。—————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
—————————————————————————————————
如下:type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
FInt2: Integer;
published
function GetInt1: Integer;
function GetInt2: Integer;
end; TFunc = function: Integer of object; TChild = class
private
FFunc: TFunc;
public
constructor Create;
end;implementation{ TForm1 }function TForm1.GetInt1: Integer;
begin
Result := 1;
end;function TForm1.GetInt2: Integer;
begin
Result := FInt2;
end;{ TChild }constructor TChild.Create;
begin
inherited Create;
TMethod(FFunc).Code := TForm1.MethodAddress('GetInt1');
if Assigned(FFunc) then
ShowMessage(IntToStr(FFunc));
{ 这是类实例的GetInt2方法指针 }
TMethod(FFunc).Code := Form1.MethodAddress('GetInt2');
if Assigned(FFunc) then
ShowMessage(IntToStr(FFunc)); { 这是类的GetInt2方法指针 }
TMethod(FFunc).Code := TForm1.MethodAddress('GetInt2');
if Assigned(FFunc) then
ShowMessage(IntToStr(FFunc));
end;procedure TForm1.Button1Click(Sender: TObject);
begin
TChild.Create.Free;
end;
不知道你发现没有,通过FFun调用GetInt2时就出错了。为什么调用GetInt1正确而GetInt2出错呢,是因为GetInt1中只是对常量1操作而GetInt2中操作了变量FInt2,取得FInt2就必须通过FFun.Data,而此时它为nil,也就是说相当于使用:
nil.FInt2
自然就错了。—————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
—————————————————————————————————
我是从这个帖子才开始明白的,呵呵:》—————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
—————————————————————————————————
type
TFunc = function: Integer of Object;
TReceiveThread = class(TThread)
private
FFunc: TFunc;
protected
procedure SynKernel;
procedure Execute; override;
end; TKernel = class
private
Receive: TList;
function IsCreate: Integer;
public
constructor Create;
destructor Destroy; override;
function SynReceive: Integer;
end;var
Kernel: TKernel;
Re: TReceiveThread;procedure TReceiveThread.SynKernel;
begin
FFunc:= Kernel.SynReceive;
if Assigned(FFunc) then
if FFunc=0 then
ShowMessage('not assign')
else
ShowMessage('assign');
end;procedure TReceiveThread.Execute;
begin
FreeOnTerminate := True;
Synchronize(SynKernel);
end;
function TKernel.SynReceive: Integer;
begin
Result := 0;
if Receive=nil then
Exit;
Result := 1;
end;constructor TKernel.Create;
begin
inherited;
Receive := TList.Create;
end;destructor TKernel.Destroy;
begin
Receive.Free;
inherited;
end;function TKernel.IsCreate: Integer;
begin
if Receive=nil then
Result := 0
else Result := 1;
end;