关于如何在线程中等待数据并将其写入文件的最佳实践?

Nix*_*Nix 5 delphi multithreading thread-safety delphi-2010

我正在编写多线程应用程序.我有两个主题.On用于将一些数据从设备传输到全局数据缓冲区,其次用于将这些数据写入文件.

从设备到缓冲区的数据是异步传输的.第二个线程的目的应该是等待指定数量的数据写入主数据缓冲区,最后将其写入文件.

那么第一个线程在DLL中,第二个在主应用程序中.我暂时用事件来解决这个问题.第一个线程将数据从设备传输到主数据缓冲区并对数据进行计数,当传输指定数量的数据时,它会设置一个事件.第二个等待事件被发出信号,当它运行时,它运行一些数据存储的代码.很简单,因为它工作.

  Thread1.Execute:

  var DataCount, TransferedData: Integer;

  DataCounter := 0;
  while not Terminted do
  begin
    TransferData(@pData, TransferedData);
    Inc(DataCounter, TransferedData)
    if DataCounter >= DataCountToNotify then SetEvent(hDataCount);
  end;



  Thread2.Execute:

  hndlArr[0] := hDataCount;
  hndlArr[1] := hTerminateEvent;

  while (not Terminated) do
  begin
    wRes := WaitForMultipleObjects(HandlesCount, Addr(hndlArr), false, 60000);
    case wRes of
      WAIT_OBJECT_0:
        begin
          Synchronize(WriteBuffer);                   // call it from main thread
          ResetEvent(hndlArr[0]);
        end;
      WAIT_OBJECT_0 + 1:
        begin
          ResetEvent(hTerminateEvent);
          break;
        end;
      WAIT_TIMEOUT:  Break;
    end;
  end;
Run Code Online (Sandbox Code Playgroud)

现在我想让第二个线程更独立...所以我可以创建第二个线程的多个实例,我不需要等待第一个线程.我想将计算部分代码的数据从第一个线程移动到第二个线程,因此我不再需要在第一个线程中进行数据计数.第一个将仅用于数据传输目的.

我想使用第二个作为数据计数器并存储数据.但现在我必须循环并不断手动检查指定的数据量.如果我有while循环我将不得不添加一些睡眠,所以第二个线程不会降低计算机性能,但我不知道应该睡多久,而firts线程中的数据传输速度不是恒定的,因此在第二个线程中的计数速度会有所不同.

我猜这个代码示例不好:

  Thread2.Execute:
  var DataCount: Integer;
  DataIdx1 := GetCurrentDataIdx; 
  while (not Terminated) do
  begin     
    if (GetCurrentDataIdx - DataIdx1) >= DataCountToNotify then 
    begin
      Synchronize(WriteBuffer);
      DataIdx1 := GetCurrentIdx;
    end;
    sleep(???);
  end;
Run Code Online (Sandbox Code Playgroud)

所以我的问题是什么是解决数据计数问题并将其存储在第二个线程中的最佳方法?您有什么经验和建议?

Mar*_*mes 5

你有一些问题.@LU RD已经指出了一个 - 不要同步不需要同步的东西.目前还不清楚'WriteBuffer'是做什么的,但是我使用的文件系统和所有数据库都可以让一个线程打开一个文件/表并写入它们.

你的缓冲系统可能会引起一些注意.是否有一些"指定的数据量"或者这是一个允许懒惰写作的名义数字?

通常,生产者和消费者线程在队列上交换多个缓冲区指针,因此避免共享任何单个缓冲区.鉴于这是一个DLL,所以内存管理调用可能会有问题,我可能会通过在启动时创建一个缓冲池来为系统传输数据来避免它们.我会使用缓冲类而不仅仅是指向内存的指针,但这并不是绝对必需的(更简单/灵活/安全).

Sleep()循环是线程之间通信的一种非常糟糕的方式.Sleep()确实有它的用途,但这不是其中之一.Delphi/Windows有很多同步机制 - 事件,信号量,互斥量等 - 使这种轮询变得不必要.

LU RD还提到了并行处理必须保留其顺序的数据的问题.这通常需要另一个线程,列表样式集合和序列号.我不会尝试,直到你有线程间通信运行良好.