Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
调用TThread.Synchronize时System.TMonitor.GetFieldAddress中存在访问冲突,已使用Delphi XE5编译_Delphi_Delphi Xe5 - Fatal编程技术网

调用TThread.Synchronize时System.TMonitor.GetFieldAddress中存在访问冲突,已使用Delphi XE5编译

调用TThread.Synchronize时System.TMonitor.GetFieldAddress中存在访问冲突,已使用Delphi XE5编译,delphi,delphi-xe5,Delphi,Delphi Xe5,调用TThread.Synchronize时System.TMonitor.GetFieldAddress中存在间歇性访问冲突,使用Delphi XE5编译 精确时间源(硬件)应该每秒更新GUI一次其状态。非VCL线程管理它,然后调用Synchronize更新GUI。每秒10000-100000次中断后,VCL线程出现访问冲突,此时实际上没有调用要同步的函数,TThread.Synchronize永远不会返回 非VCL线程堆栈和代码段: :77a47074 ntdll.KiFastSystemC

调用TThread.Synchronize时System.TMonitor.GetFieldAddress中存在间歇性访问冲突,使用Delphi XE5编译

精确时间源(硬件)应该每秒更新GUI一次其状态。非VCL线程管理它,然后调用Synchronize更新GUI。每秒10000-100000次中断后,VCL线程出现访问冲突,此时实际上没有调用要同步的函数,TThread.Synchronize永远不会返回

非VCL线程堆栈和代码段:

:77a47074 ntdll.KiFastSystemCallRet
:77a46a14 ntdll.ZwWaitForSingleObject + 0xc
:751fc3d3 kernel32.WaitForSingleObjectEx + 0x43
:751fc382 kernel32.WaitForSingleObject + 0x12
System.SysUtils.WaitForSyncWaitObj(???,???)
System.SysUtils.WaitOrSignalObj(???,$FFFFFFFF,???)
System.TMonitor.Wait($4843710,4294967295)
System.TMonitor.Wait($4853490,$2E30D40,4294967295)
System.Classes.TThread.Synchronize($898B0A0,False)
System.Classes.TThread.Synchronize((TimeChannel.TTimeChannel.UpdateReaderStatus,$A81CB40))
...
      if ( not Terminated ) and ( not Paused ) and assigned( self ) and assigned( fParent ) then
      begin
        Inc( fParent.fUpdateReaderStatusSyncronizeCounter ); // Counter to see if fParent.UpdateReaderStatus is actually called when Synchronize is called.
        Synchronize( fParent.UpdateReaderStatus ); // Called about once per second.  Runs for around a day before problem.  Thread never returns from here after problem happens.
...
TimeChannel.tRdrStatusControl.Execute
System.Classes.ThreadProc($898B080)
System.ThreadWrapper($8975DA0)
:751fee1c kernel32.BaseThreadInitThunk + 0x12
:77a6399b ntdll.RtlInitializeExceptionChain + 0xef
:77a6396e ntdll.RtlInitializeExceptionChain + 0xc2
...
PROCEDURE tTimeChannel.UpdateReaderStatus;
BEGIN
  try
    Inc( fUpdateReaderStatusCounter ); // counter remains 1 behind the other counter when problem occurs, so UpdateReaderStatus never got called that time and the other thread never returned from Synchronize.

...

class function TMonitor.GetFieldAddress(const AObject: TObject): PPMonitor;
begin
  Result := PPMonitor(PByte(AObject) + AObject.InstanceSize - hfFieldSize + hfMonitorOffset); // Access Violation, read of address 0
end;

...

System.TMonitor.GetFieldAddress(nil)
System.TMonitor.GetMonitor(???)
System.TMonitor.Pulse(nil)

...

function CheckSynchronize(Timeout: Integer = 0): Boolean;
var
  SyncProc: PSyncProc;
  LocalSyncList: TList;
begin
{$IF Defined(MSWINDOWS)}
  if SyncEvent = 0 then
    Exit(False);
{$ELSEIF Defined(POSIX)}
  if (SyncEvent.ReadDes = 0) or (SyncEvent.WriteDes = 0) then
    Exit(False);
{$ENDIF POSIX}
  if TThread.CurrentThread.ThreadID <> MainThreadID then
    raise EThread.CreateResFmt(@SCheckSynchronizeError, [TThread.CurrentThread.ThreadID]);
  if Timeout > 0 then
    WaitForSyncEvent(Timeout)
  else
    ResetSyncEvent;
  LocalSyncList := nil;
  TMonitor.Enter(ThreadLock);
  try
    Pointer(LocalSyncList) := AtomicExchange(Pointer(SyncList), Pointer(LocalSyncList));
    try
      Result := (LocalSyncList <> nil) and (LocalSyncList.Count > 0);
      if Result then
      begin
        while LocalSyncList.Count > 0 do
        begin
          SyncProc := LocalSyncList[0];
          LocalSyncList.Delete(0);
          TMonitor.Exit(ThreadLock);
          try
            try
              if Assigned(SyncProc.SyncRec.FMethod) then
                SyncProc.SyncRec.FMethod()
              else if Assigned(SyncProc.SyncRec.FProcedure) then
                SyncProc.SyncRec.FProcedure();
            except
              if not SyncProc.Queued then
                SyncProc.SyncRec.FSynchronizeException := AcquireExceptionObject
              else
                raise;
            end;
          finally
            TMonitor.Enter(ThreadLock);
          end;
          if not SyncProc.Queued then
            TMonitor.Pulse(SyncProc.Signal) // SyncProc.Signal is nil <----------------
          else
          begin
            Dispose(SyncProc.SyncRec);
            Dispose(SyncProc);
          end;
        end;
      end;
    finally
      LocalSyncList.Free;
    end;
  finally
    TMonitor.Exit(ThreadLock);
  end;
end;

...

System.Classes.CheckSynchronize(???)
Vcl.Forms.TApplication.WndProc((0, 0, 0, 0, 0, 0, (), 0, 0, (), 0, 0, ()))
System.Classes.StdWndProc(590087812,0,0,0)
:752ac4e7 ; C:\Windows\system32\USER32.dll
:752ac5e7 ; C:\Windows\system32\USER32.dll
:752acc19 ; C:\Windows\system32\USER32.dll
:752acc70 USER32.DispatchMessageW + 0xf
Vcl.Forms.TApplication.ProcessMessage(???)
:006202fc TApplication.ProcessMessage + $F8
VCL线程堆栈和代码段:

:77a47074 ntdll.KiFastSystemCallRet
:77a46a14 ntdll.ZwWaitForSingleObject + 0xc
:751fc3d3 kernel32.WaitForSingleObjectEx + 0x43
:751fc382 kernel32.WaitForSingleObject + 0x12
System.SysUtils.WaitForSyncWaitObj(???,???)
System.SysUtils.WaitOrSignalObj(???,$FFFFFFFF,???)
System.TMonitor.Wait($4843710,4294967295)
System.TMonitor.Wait($4853490,$2E30D40,4294967295)
System.Classes.TThread.Synchronize($898B0A0,False)
System.Classes.TThread.Synchronize((TimeChannel.TTimeChannel.UpdateReaderStatus,$A81CB40))
...
      if ( not Terminated ) and ( not Paused ) and assigned( self ) and assigned( fParent ) then
      begin
        Inc( fParent.fUpdateReaderStatusSyncronizeCounter ); // Counter to see if fParent.UpdateReaderStatus is actually called when Synchronize is called.
        Synchronize( fParent.UpdateReaderStatus ); // Called about once per second.  Runs for around a day before problem.  Thread never returns from here after problem happens.
...
TimeChannel.tRdrStatusControl.Execute
System.Classes.ThreadProc($898B080)
System.ThreadWrapper($8975DA0)
:751fee1c kernel32.BaseThreadInitThunk + 0x12
:77a6399b ntdll.RtlInitializeExceptionChain + 0xef
:77a6396e ntdll.RtlInitializeExceptionChain + 0xc2
...
PROCEDURE tTimeChannel.UpdateReaderStatus;
BEGIN
  try
    Inc( fUpdateReaderStatusCounter ); // counter remains 1 behind the other counter when problem occurs, so UpdateReaderStatus never got called that time and the other thread never returned from Synchronize.

...

class function TMonitor.GetFieldAddress(const AObject: TObject): PPMonitor;
begin
  Result := PPMonitor(PByte(AObject) + AObject.InstanceSize - hfFieldSize + hfMonitorOffset); // Access Violation, read of address 0
end;

...

System.TMonitor.GetFieldAddress(nil)
System.TMonitor.GetMonitor(???)
System.TMonitor.Pulse(nil)

...

function CheckSynchronize(Timeout: Integer = 0): Boolean;
var
  SyncProc: PSyncProc;
  LocalSyncList: TList;
begin
{$IF Defined(MSWINDOWS)}
  if SyncEvent = 0 then
    Exit(False);
{$ELSEIF Defined(POSIX)}
  if (SyncEvent.ReadDes = 0) or (SyncEvent.WriteDes = 0) then
    Exit(False);
{$ENDIF POSIX}
  if TThread.CurrentThread.ThreadID <> MainThreadID then
    raise EThread.CreateResFmt(@SCheckSynchronizeError, [TThread.CurrentThread.ThreadID]);
  if Timeout > 0 then
    WaitForSyncEvent(Timeout)
  else
    ResetSyncEvent;
  LocalSyncList := nil;
  TMonitor.Enter(ThreadLock);
  try
    Pointer(LocalSyncList) := AtomicExchange(Pointer(SyncList), Pointer(LocalSyncList));
    try
      Result := (LocalSyncList <> nil) and (LocalSyncList.Count > 0);
      if Result then
      begin
        while LocalSyncList.Count > 0 do
        begin
          SyncProc := LocalSyncList[0];
          LocalSyncList.Delete(0);
          TMonitor.Exit(ThreadLock);
          try
            try
              if Assigned(SyncProc.SyncRec.FMethod) then
                SyncProc.SyncRec.FMethod()
              else if Assigned(SyncProc.SyncRec.FProcedure) then
                SyncProc.SyncRec.FProcedure();
            except
              if not SyncProc.Queued then
                SyncProc.SyncRec.FSynchronizeException := AcquireExceptionObject
              else
                raise;
            end;
          finally
            TMonitor.Enter(ThreadLock);
          end;
          if not SyncProc.Queued then
            TMonitor.Pulse(SyncProc.Signal) // SyncProc.Signal is nil <----------------
          else
          begin
            Dispose(SyncProc.SyncRec);
            Dispose(SyncProc);
          end;
        end;
      end;
    finally
      LocalSyncList.Free;
    end;
  finally
    TMonitor.Exit(ThreadLock);
  end;
end;

...

System.Classes.CheckSynchronize(???)
Vcl.Forms.TApplication.WndProc((0, 0, 0, 0, 0, 0, (), 0, 0, (), 0, 0, ()))
System.Classes.StdWndProc(590087812,0,0,0)
:752ac4e7 ; C:\Windows\system32\USER32.dll
:752ac5e7 ; C:\Windows\system32\USER32.dll
:752acc19 ; C:\Windows\system32\USER32.dll
:752acc70 USER32.DispatchMessageW + 0xf
Vcl.Forms.TApplication.ProcessMessage(???)
:006202fc TApplication.ProcessMessage + $F8
。。。
程序tTimeChannel.UpdateReaderStatus;
开始
尝试
公司(fUpdateReaderStatusCounter);//当问题发生时,计数器在另一个计数器后面保持1,因此当时从未调用UpdateReaderStatus,而另一个线程也从未从Synchronize返回。
...
类函数TMonitor.GetFieldAddress(const AOObject:ToObject):PPMonitor;
开始
结果:=PPMonitor(PByte(AObject)+AObject.InstanceSize-hfFieldSize+hfMonitorOffset);//访问冲突,读取地址0
结束;
...
System.TMonitor.GetFieldAddress(无)
System.TMonitor.GetMonitor(?)
系统TMonitor.Pulse(无)
...
函数CheckSynchronize(超时:整数=0):布尔值;
变量
SyncProc:PSyncProc;
LocalSyncList:TList;
开始
{$IF-Defined(MSWINDOWS)}
如果SyncEvent=0,则
退出(假);
{$ELSEIF已定义(POSIX)}
如果(SyncEvent.ReadDes=0)或(SyncEvent.WriteDes=0),则
退出(假);
{$ENDIF POSIX}
如果TThread.CurrentThread.ThreadID MainThreadID,则
提高EThread.CreateResFmt(@SCheckSynchronizeError[TThread.CurrentThread.ThreadID]);
如果超时>0,则
WaitForSyncEvent(超时)
其他的
重置同步事件;
LocalSyncList:=nil;
t监控输入(螺纹锁紧);
尝试
指针(LocalSyncList):=AtomicExchange(指针(SyncList),指针(LocalSyncList));
尝试
结果:=(LocalSyncList nil)和(LocalSyncList.Count>0);
如果结果是这样的话
开始
当LocalSyncList.Count>0时
开始
SyncProc:=LocalSyncList[0];
LocalSyncList.Delete(0);
t监控出口(螺纹锁紧);
尝试
尝试
如果已分配(SyncProc.SyncRec.FMethod),则
SyncProc.SyncRec.FMethod()
否则,如果已分配(SyncProc.SyncRec.FProcedure),则
SyncProc.SyncRec.FProcedure();
除了
如果没有SyncProc.排队,则
SyncProc.SyncRec.FSynchronizeException:=AcquireExceptionObject
其他的
提高;
结束;
最后
t监控输入(螺纹锁紧);
结束;
如果没有SyncProc.排队,则

TMonitor.Pulse(SyncProc.Signal)//SyncProc.Signal为零。其他问题的一些答案表示要避免使用Synchronize()。它是从根本上被破坏了,还是很容易出错?其他一些线程也调用synchronize和queue。其他线程是否可能破坏了synchronize中的某些内容,并且错误最终出现在该线程中?
SyncProc.Signal
对于
TThread.synchronize()
请求,决不能为零
Synchronize()
创建一个
TObject
并将其分配给
SyncProc.Signal
,并将
SyncProc.Queued
设置为False,然后再将SyncProc项目添加到队列中。因此,当
SyncProc.Queued
为False时,
SyncProc.Signal
可能为零的唯一方法是内存被损坏,而队列项是该损坏的不幸受害者。这不是
Synchronize()
本身的错误,因此肯定有其他东西会损坏内存。
TMonitor
仍然存在缺陷这一点很有可能。您能否将代码减少到最低限度,在短时间内强制出错,即通过更频繁的更新?