-1

TStream を受け取るプロシージャを開発しました。ただし、すべてのタイプのストリーム相続人の送信を許可するための基本タイプ。

この手順は、各コアに 1 つのスレッド、または複数のスレッドを作成することを目的としています。各スレッドはストリーム データ (読み取り専用) の詳細な分析を実行します。Pascal クラスは参照によって割り当てられ、値によって割り当てられることはないため、読み取り位置がインターカラーであるため、スレッドの衝突が発生します。

これを修正するには、メモリ内の最後の TStream を 2 倍にして新しい変数を割り当てる手順をすべて実行する必要があります。このようにして、各スレッドが一意の TStream を持つように TStream を十分な数だけ複製できます。非常にスレッド ライブラリ メモリの終了後。

注: 手順は DLL 内にあり、スレッドは機能します。

注 2: 目標は、プロシージャが必要なサービスをすべて実行することです。TStreamだけでなく、TStream の配列を簡単に渡すことができます。でも欲しくない!目的は、サービスが完全に手順によって提供されることです。

これを行う方法はありますか?

ありがとうございました。

添加:

低レベルのアイデアはありましたが、Pascal に関する知識は限られています。

  1. メモリ内のオブジェクトのアドレスとそのサイズを特定します。
  2. 元のオブジェクトと同じサイズの新しいアドレスをメモリに作成します。
  3. コンテンツ (生) オブジェクト全体をこの新しいアドレスにコピーします。
  4. メモリ内のこの新しいアドレスを指す TStream へのポインタを作成します。

これは機能しますか、それともばかですか?? はいの場合、操作方法は?例 お願いします!

2º 追加:

例として、プログラムが暗号化されたストリームに対してブルート フォース攻撃を実行するとします (適用できないため、単なる例です)。

シーン: 8 コアの CPU で 30GB のファイル:

1º - TMemoryStream:

8 つの TMemoryStream を作成し、各 TMemoryStream のファイルの内容全体をコピーします。これにより、240GB RAM が同時に使用されることになります。私はこの壊れた考えを考えます。さらに、マルチスレッドを使用しないと、処理時間が最速のポイントまで増加します。ファイル全体をメモリに読み込んでロードし、分析を開始する必要がありました。壊れた!

 * TMemoryStream の不適切な代替手段は、メモリを占有しないように、ファイルを 100MB/コア (800MB) ずつ TMemoryStream にゆっくりとコピーすることです。したがって、各スレッドは 100MB しか見えず、ファイル全体を完了するまでメモリを解放します。しかし問題は、DLL で Synchronize() 関数が必要になることです。これは、Synchronize () で質問を開くと、うまくいかないことがわかっています。DLL はエラーなしでフリーズし、クラッシュします。

2º - TFileStream:

これは私の意見では悪いです。TStream を取得し、8 つの TFileStream を作成して、各 TFileStream の 30GB をすべてコピーします。ディスク上で 240GB を占有するため、これは大きな値であり、HDD に対してもです。HD での読み取りおよび書き込み時間 (コピー) により、マルチスレッドの実装はシングル スレッドよりも時間がかかることが判明します。壊れた!

結論: 上記の 2 つの方法では、synchronize() を使用して各スレッドをキューに入れ、ファイルを読み取る必要があります。したがって、マルチコア CPU でも、スレッドは同時に動作しません。彼がファイルに同時にアクセスできたとしても (複数の TFileStream を直接作成する)、オペレーティング システムはファイルを一度に 1 つずつ読み取るために依然として enfileiraria スレッドを実行します。HDD は完全にスレッドセーフではないため、彼は 2 つのデータを読み取ることはできません。同時に 。これは HDD の物理的な制限です。ただし、OS のキューイング管理は、手動で synchronize() を実装する場合とは異なり、はるかに効果的であり、潜在的なボトルネックを効率的に減らします。これは、TStream のクローンを作成するという私の考えを正当化するものであり、ファイル アクセス キューを管理するためのすべての作業を SO に任せることになります。何の介入もなしに。

上記の例では、8 つのスレッドが同じ Stream を異なる方法で同時に分析する必要があります。スレッドは、提供された Stream の種類を認識していないため、ファイル Stream、インターネットからのストリーム、または小さな TStringStream でさえある可能性があります。メイン プログラムは、1 つのストリアンのみを作成し、構成パラメーターを使用します。簡単な例:

TModeForceBrute = (M1, M2, M3, M4, M5...)
TModesFB = set of TModeForceBrute;

TService = record
  stream: TStream;
  modes: array of TModesFB;
end;

たとえば、ストリーム M1 のみ、M2 のみ、または両方 [M1、M2] を分析できる必要があります。TModesFB 構成は、ストリームの分析方法を変更します。タスクリストとして機能する配列「modes」の各項目は、異なるスレッドによって処理されます。タスク リストの例 (JSON 表現):

{
  Stream: MyTstream,
  modes: [
    [M1, m5],
    [M1],
    [M5, m2],
    [M5, m2, m4, m3],
    [M1, m1, m3]
  ]
}

注: アナライザーでは [m1] + [m2] <> [m1, m2]。

プログラム内:

function analysis(Task: TService; maxCores: integer): TMyResultType; external 'mydll.dll';

DLL の場合:

// Basic, simple and fasted Exemple! May contain syntax errors or logical.
function analysis(Task: TService; maxCores: integer): TMyResultType; 
var 
  i, processors : integer;

begin
  processors := getCPUCount();

  if (maxCores < processors) and (maxCores > 0) then
    processors := maxCores;

  setlength (globalThreads, processors);

  for i := 0 to processors - 1 do
    // It is obvious that the counter modes in the original is not the same counter processors.
    if i < length(Task.modes) then begin
      globalThreads[i] := TAnalusysThread.create(true, Task.stream, Task.modes[i])
      globalThreads[i].start();
    end;

  [...]
end;

注: シングル スレッドの場合、プログラムは問題なく動作し、既知のエラーはありません。

各スレッドに特定のタイプの分析を処理してもらいたいのですが、DLL で Synchronize() を使用できません。理解?適切でクリーンなソリューションはありますか?

4

2 に答える 2

1

ストリームのクローンは、次のようなコードです。

streamdest:=TMemoryStream.create; 
streamsrc.position:=0; 
streamdest.copyfrom(streamdest); 
streamsrc.position:=0; 
streamdest.position:=0;

ただし、DLL にはライブラリとライブラリの状態の独自のコピーがあるため、DLL の境界を越えて処理を行うのは困難です。これは現在推奨されていません。

于 2016-02-14T21:16:54.533 に答える
0

誰も本当に良い解決策を持っていないと思ったので、私は私の質問に答えています。無いからなのかな!

そこで、同期にTRTLCriticalSectionを使用し、メモリ バッチ 50MB の部分的な負荷で TMemoryStream を使用して機能するソリューションについて、Marco van de VoortKen Whiteのアイデアを採用しました。

このソリューションには、追加 2 で述べたのと同じ欠点も含まれています。彼らは:

  1. HDD へのアクセスのキューイングは、オペレーティング システムではなく、私のプログラムの責任です。
  2. 1 つのスレッドは、メモリ内で同じデータを 2 回運びます。
  3. プロセッサの速度によっては、スレッドが高速な 50MB のメモリを適切に分析する場合があります。一方、メモリのロードは非常に遅くなる可能性があります。これにより、複数のスレッドが順次実行され、マルチスレッドを使用する利点が失われます。これは、すべてのスレッドがファイルへのアクセスを混雑させ、単一のスレッドであるかのように順次実行されるためです。

したがって、このソリューションは汚いソリューションだと思います。しかし、今のところそれは機能します!

以下に簡単な例を示します。これは、この適応には論理および/または構文の明らかなエラーが含まれている可能性があることを意味します。しかし、実証するには十分です。

問題の同じ例を使用すると、現在の「分析」を渡す代わりに、プロセスへのポインターが渡されます。この手順では、ストリーム バッチの読み取りを 50MB 同期させます。

DLL とプログラムの両方:

TLotLoadStream = function (var toStm: TMemoryStream; lot, id: integer): int64 of object;

TModeForceBrute = (M1, M2, M3, M4, M5...)
TModesFB = set of TModeForceBrute;

TaskTService = record
  reader: TLotLoadStream; {changes here <<<<<<< } 
  modes: array of TModesFB;
end;

プログラム内:

type
{ another code here }
TForm1 = class(TForm)
  { another code here }

  CS    : TRTLCriticalSection;  
  stream: TFileStream;
  function MyReader(var toStm: TMemoryStream; lot: integer): int64 of object;

  { another code here }
end;

function analysis(Task: TService; maxCores: integer): TMyResultType; external 'mydll.dll';

{ another code here }

implementation

{ another code here }

function TForm1.MyReader(var toStm: TMemoryStream; lot: integer): int64 of object;
const
  lotSize = (1024*1024) * 50; // 50MB

var
  ler: int64;

begin
  result := -1;
  { 
    MUST BE PERFORMED PREVIOUSLY - FOR EXAMPLE IN TForm1.create()
    InitCriticalSection (self.CriticalSection);
  }   

  toStm.Clear;
  ler    := 0;

  { ENTERING IN CRITICAL SESSION  }
  EnterCriticalSection(self.CS);

  { POSITIONING IN LOT OF BEGIN}
  self.streamSeek(lot * lotSize, soBeginning);

  if (lot = 0) and (lotSize >= self.stream.size) then
    ler := self.stream.size
  else
    if self.stream.Size >= (lotSize + (lot * lotSize)) THEN
      ler := lotSize
    else
      ler := (self.stream.Size) - self.stream.Position; // stream inicia em 0?

  { COPYNG }
  if (ler > 0) then
    toStm.CopyFrom(self.stream, ler);

  { LEAVING THE CRITICAL SECTION }
  LeaveCriticalSection(self.CS);

  result := ler; 
end;

DLL の場合:

{ another code here }
// Basic, simple and fasted Exemple! May contain syntax errors or logical.
function analysis(Task: TService; maxCores: integer): TMyResultType; 
var 
  i, processors : integer;

begin
  processors := getCPUCount();

  if (maxCores < processors) and (maxCores > 0) then
    processors := maxCores;

  setlength (globalThreads, processors);

  for i := 0 to processors - 1 do
    // It is obvious that the counter modes in the original is not the same counter processors.
    if i < length(Task.modes) then begin
      globalThreads[i] := TAnalusysThread.create(true, Task.reader, Task.modes[i])
      globalThreads[i].start();
    end;

  { another code here }
end;

DLL スレッド クラス:

type
{ another code here }
MyThreadAnalysis = class(TThread)
  { another code here }

  reader: TLotLoadStream;
  procedure Execute;

  { another code here }
end;

{ another code here }

implementation

{ another code here }

procedure MyThreadAnalysis.Execute;
var
  Stream: TMemoryStream;
  lot: integer;     

  {My analyzer already all written using buff, the job of rewriting it is too large, then it is so, two readings, two loads in memory, as I already mentioned in the question!}   
  buf: array[1..$F000] of byte; // 60K

begin         
  lot    := 0;  
  Stream := TMemoryStream.Create;     
  self.reader(stream, lot);

  while  (assigned(Stream)) and (Stream <> nil) and (Stream.Size > 0) then begin
    Stream.Seek(0, soBeginning);      

    { 2º loading to memory buf }        
    while (Stream.Position < Stream.Size) do begin
      n := Stream.read(buf, sizeof(buf));     

      { MY CODE HERE }
    end;

    inc(lot);
    self.reader(stream, lot, integer(Pchar(name)));     
  end;
end;

ご覧のとおり、これはその場しのぎの解決策です。データへのアクセスが私のプログラムではなくオペレーティング システムの責任となるような方法で、フロー コントローラーを 2 倍にすることができるクリーンなソリューションを見つけたいと思っています。

于 2016-02-21T14:33:17.693 に答える