Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.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
Linux 为什么线程只以较大的间隔进行同步?_Linux_Multithreading_Zeromq_Freepascal - Fatal编程技术网

Linux 为什么线程只以较大的间隔进行同步?

Linux 为什么线程只以较大的间隔进行同步?,linux,multithreading,zeromq,freepascal,Linux,Multithreading,Zeromq,Freepascal,FPC 3.0.0,Lazarus 1.6.0 我在Linux机器上有两个线程(稍后我会在Windows上检查,这段代码应该是跨平台的),主线程和客户端线程。客户端线程的目的是提供非阻塞请求-应答网络功能 pascal客户机(请求者)与服务器通信,使用python(replier)编写 我正在使用ZeroMQREQ/REP来处理底层的东西,即最后的版本 在高层,创建和启动客户机线程如下: //from the main thread FClientThread.Create('tcp://loc

FPC 3.0.0,Lazarus 1.6.0

我在Linux机器上有两个线程(稍后我会在Windows上检查,这段代码应该是跨平台的),主线程和客户端线程。客户端线程的目的是提供非阻塞请求-应答网络功能

pascal
客户机(请求者)与服务器通信,使用
python
(replier)编写

我正在使用
ZeroMQ
REQ/REP
来处理底层的东西,即最后的版本

在高层,创建和启动客户机线程如下:

//from the main thread
FClientThread.Create('tcp://localhost:5020');
FClientThread.Start;
要发送请求,请执行以下操作:

//from the main thread
FClientThread.SendRequest('im_requesting_stuff',-1,'give_it_to_me');
Sleep(1000)
FClientThread.SendRequest('requesting',-1,'gimme_more'); 

//the TClientThread descends from TThread.
procedure TClientThread.SendRequest(ACode: string; ATrialIndex: integer;
  ARequest: string);
begin
  FRequest := ARequest;
  FCode := ACode;
  FTrialIndex := IntToStr(ATrialIndex);
  RTLeventSetEvent(FRTLEvent);
end;

procedure TClientThread.Execute;
var
  AMessage : UTF8String;
begin
  while not Terminated do
    begin
      AMessage := '';
      RTLeventWaitFor(FRTLEvent);

      FRequester.send( FRequest );
      FRequester.recv( AMessage ); // blocking code,
                                   // that is why it is inside the thread

      // *****************************************************************************
      // BUG: These vars are being filled with the last values of
      //            ( 'FTrialIndex',               'AMessage',               'FCode' )
      FMsg := #40#39 + FTrialIndex + #39#44#32#39 + AMessage + #39#44#32#39 + FCode + #39#41;
      // 
      // *****************************************************************************

      Synchronize( @Showstatus );
    end;
end;  
服务器端以非阻塞方式工作,单线程:

为True时:
msg=self.socket.recv(flags=zmq.NOBLOCK)
#做事
self.socket.send(响应)
只有在非常短的时间间隔内多次调用
.SendRequest()
时(例如,没有
sleep()
),才会出现注释错误(重复上次调用)

我预计会有一些损失,但我不希望重复,因为我正在明确地等待主线程返回

有什么建议吗

致意


编辑1:

ZMQ版本 python 帕斯卡 有关版本,请参阅提交(50a28b4b72c531536452ee5d79e19f5960c9f7c7)


编辑2:

日志 图例:

LogTickCount:('REQTickCount','TestCode:DeltaTime')

将Fvariable复制到局部变量之前:

4476.028775652:[debug]TClockThread.Execute:Start 140736007759616
4476.087363892:('4476.08701411','S:7.316086894')
4478.567764596:(‘4478.56744415’,‘R:9.828251263’)
4478.923743380:('4478.92343718','R:10.192552661')
4479.134910639:[调试]C:预期是下一个
4479.166311115:('4479.16600296','R:10.424417498')//错误
4479.201287606:('4479.20099538','R:10.424417498')
4483.037278107:('4483.03664644','2b:14.32258449')
4483.8644929:('4483.86663063','*R:15.153748820')
4484.278650579:('4484.27829493','R:15.562894551')
4484.552199446:[debug]C:预期是下一个
//数据丢失
4484.594517381:('4484.59364657','R:15.841710775')
4490.088956444:('4490.08862455','1b:21.318677098')
4490.465529156:(‘4490.46522659’,‘R:21.738692793’)
4490.744151772:('4490.74376093','R:22.027325175')
4491.047253601:[debug]C:应为下一个
4491.064188821:('4491.0638315','R:22.336764091')//错误
4491.100142009:('4491.09978804','R:22.336764091')
4496.084726117:('4496.08441014','2a:27.320218402')
4496.494107080:(‘4496.49378719’,‘R:27.762184396’)
4496.816623032:('4496.81630259','R:28.100685410')
4497.088603481:[调试]C:预期是下一个
//数据丢失
4497.132445971:('4497.13214788','R:28.378107825')
将Fvariables复制到局部变量后(注意:纯lucky没有丢失数据):

8183.233467050:[debug]TClockThread.Execute:Start 140736477513472
8183.29973049:('8183.29946881','S:10.678368191')
8183.751976738:(‘8183.7516616’,‘R:11.182574383’)
8184.262027198:('8184.26170452','R:11.690292332')
8184.501553063:[debug]C:下一个应该是
8184.517362396:('8184.51705341','C:11.952652441')
8184.552388891:('8184.55206258','R:11.950063743')
8189.291033037:('8189.29070225','2b:16.683417064')
8189.880999859:(‘8189.88067746’,‘R:17.299351333’)
8190.257476710:('8190.25714788','R:17.699402216')
8190.51557895:[debug]C:下一个应该是
8190.553234830:('8190.55290992','C:17.966527084')
8190.588187291:('8190.5878607','R:17.964049297')
8196.243242766:('8196.24264239','1b:23.683231358')
8196.758162472:('8196.75784342','*R:24.200630247')
8196.964202600:('8196.96383131','R:24.397590095')
8197.119091206:[debug]C:下一个应该是
8197.142731450:('8197.14240346','C:24.570427216')
8197.177078782:('8197.17673878','R:24.567590990')
8208.243614030:('8208.24296169','2a:35.685189479')
8208.659747197:(‘8208.65940133’,‘R:36.092803071’)
8208.794614317:('8208.79431818','R:36.230488258')
8208.909275842:[debug]C:下一个应该是
8208.935924407:('8208.93559782','C:36.360198934')
8208.970681025:('8208.9703712','R:36.357781493')
事实证明,对于我的具体实现,使用关键部分是不必要的


编辑3.:

请注意,当前问题不是关于数据丢失(排队请求)。它是关于线程同步(变量共享)。关于数据丢失,使用
Sleep()
仅仅是一种黑客行为(您应该使用队列)


我已经用
Sleep(10)
测试了代码,它减少了数据丢失的机会。但你应该注意,这是一个幸运的黑客行为。

这可能是因为日程安排。您使用
FClientThread.Create('Create')创建了一个可执行代码(线程)tcp://localhost:5020');FClientThread.Start告诉O.S.“线程准备好了,您可以随时安排它”

使用
FClientThread.SendRequest发送参数('im_requesting_stuff',-1,'give_it_to_me')不保证线程立即运行。当前上下文将是主线程,调度程序还不能启动新创建的线程。而
Sleep(1000)
在调度透视图中变化不大。如果您的代码与睡眠(1000)
配合使用,那么请相信我,这纯粹是运气;为什么?您无法确定调度程序何时调度线程,这就是原因。。因此,当您调用
FClientThread.SendRequest('requising',-1,'gimme_more')您仍然在主线程中,并设置客户端线程的变量。每当您的客户机线程被调度时,它都使用其当前变量,在本例中设置了两次

我认为阻塞参数传递机制应该在
SendRequest
方法中实现。确保有很多方法可以实现

长话短说
# zmq
print zmq.zmq_version()
# 4.1.2

# pyzmq
print zmq.__version__
# 15.1.0
// zmq
ZMQVersion(minor,major,patch)
WriteLn(minor,major,patch)
// 3.2.5
TClientThread = class( TThread )
private
  FCriticalSection: TCriticalSection;
  ...
end;

//the TClientThread descends from TThread.
procedure TClientThread.SendRequest(ACode: string; ATrialIndex: integer;
  ARequest: string);
begin
  FCriticalSection.Enter;
  try
    FRequest := ARequest;
    FCode := ACode;
    FTrialIndex := IntToStr(ATrialIndex);
  finally
    FCriticalSection.Leave;
  end;
  RTLeventSetEvent(FRTLEvent);
end;

procedure TClientThread.Execute;
var
  lRequest: string;
  AMessage : UTF8String;
begin
  while not Terminated do
    begin
      AMessage := '';
      RTLeventWaitFor(FRTLEvent);

      FCriticalSection.Enter;
      try
        // copy data to local vars
        lRequest := FRequest;
      finally
        FCriticalSection.Leave;
      end;

      FRequester.send( lRequest );
      ...