Delphiのマルチスレッドの割り込み処理について

このQ&Aのポイント
  • Delphiのマルチスレッドの割り込み処理についての要約文です。
  • Delphiのマルチスレッドにおける割り込み処理について、Synchronizeメソッドの働きについて説明します。
  • Delphiのマルチスレッドの割り込み処理において、Synchronizeメソッドが待機する動作について解説します。
回答を見る
  • ベストアンサー

Delphiのマルチスレッドの割り込み処理について

Delphiのマルチスレッドの割り込み処理について教えて欲しいのですが、ファイルをスレッドオブジェクトで作成して クラス名.Execute関数内でSynchronizeメソッドを使用しています。 本にはSynchronizeメソッドは「渡したメソッドが実行され終了するまで待ちます」と書いてあり、テストプログラムを作成してもそうでした。ということはSynchronizeメソッドは普通の関数と一緒のような気がしてしまうのですが、違うのでしょうか? Procedure MyThread.Execute begin Synchronize(AAA); AAAの処理が終了するまで待機している end; Procedure TmyThread.AAA; begin 'したい処理' end;

質問者が選んだベストアンサー

  • ベストアンサー
  • SHIMAPEE
  • ベストアンサー率75% (154/203)
回答No.1

実際にプログラムを作って試した訳ではありません。見当違いでしたらすみません。 BDS2006のヘルプを見たところ、SynchronizeメソッドはDelphiの中で唯一つしかないメインVCLのスレッドを使うための方法です。すなわちスレッド間の競合の問題を「簡単に」解決する方法です。 ですから、'したい処理' 全体をSynchronizeで呼び出すのではなく、基本的には 'したい処理' はExecute内に書き、その中の競合する部分だけを切り出してSynchronizeで呼び出すようにします。 例えば、DelphiのDemoフォルダ下にあるThreadsプログラムは、PaintBoxを書き換える処理だけを切り出してSynchronizeで呼び出しています。配列に関しては各スレッドで独立しているため勝手に書き換えています。 また、競合を回避するには、TCriticalSectionクラスを使う方法もあります。'したい処理' はExecute内に書き、その中の競合する部分だけをEnter-Leaveではさむようにします。

tomojyuu
質問者

お礼

回答ありがとうございます。 DelphiのDemoフォルダ下にあるThreadsプログラムを動かしてみました。 自分でもSynchronizeメソッドの動きがわかるテストプログラムを作ってみました。わかった事はSynchronizeメソッドはメインVCLのスレッドという事...つまり字のごとしVCLのスレッドなのですね。だからVCLコンポーネントをSynchronize内で使用しないとマルチスレッドにならないのです。 例えば、demoのThreadsプログラムの「PaintBoxを書き換える処理」を グラフィックでは無く、数字にすれば、本来あるべき結果にはならないはず(推測ですが)です。

その他の回答 (1)

  • SHIMAPEE
  • ベストアンサー率75% (154/203)
回答No.2

ANo.1のお礼に対するアドバイスです。勘違いでしたらすみません。 マルチスレッドで理想的なのは、各スレッドが自由に仕事をすることです。しかし現実には「PaintBoxを書き換える処理」等の競合があるので、それを回避するために部分的にSynchronizeやTCriticalSection等を使わなければなりません。 ですから、tomojyuuさんが書かれた、 >だからVCLコンポーネントをSynchronize内で使用しないとマルチスレッドにならないのです。 >グラフィックでは無く、数字にすれば、本来あるべき結果にはならないはず(推測ですが)です。 上記は表現の違いかもしれませんが、 ・マルチスレッドにしたからこそ、スレッドセーフが保証されていないVCLコンポーネントは、競合を回避する一つの方法としてSynchronize内で使わなければならないのです。 ・グラフィックではなくスレッド個々の配列を操作するだけにすれば、そもそもSynchronizeが必要な処理がありませんので、Synchronizeを使わなくても本来あるべき結果になります。配列は正しくソートされます。 となります。

tomojyuu
質問者

お礼

2度の回答ありがとうございます。恐縮です。 <グラフィックではなく(中略)配列は正しくソートされます。 テストプログラムを作って実行した所、SHIMAPEEさんのアドバイス通りSynchronize無しでもマルチスレッドになりました。 優先順位を付けて実行したのです。

関連するQ&A

  • マルチスレッドについて

    現在”猫でもできる”の87、88章を学んでおります。 まず87章でマルチスレッドの根本的なやり方を学びましたが、いきなり疑問が浮かびました。 _beginthread関数によりスレッドをスタートさせ、この関数で登録した関数内で_endthread関数を実行し終了させていることは分かります。 しかし_beginthread関数で登録した関数に引数を渡す処理がどの部分で行われているのかわかりません。 登録する関数はvoid型で引数はvoid*型でなければいけないことは分かったのですが、プログラムのどこを見てもこの登録した関数に引数を渡す処理が行われていません。 その辺の動作の説明を分かる方でいいのでよろしくお願いします。 そして88章では排他制御のマルチスレッドを行うプログラムの製作を行っているのですが、ちょっとした疑問が浮かびました。 EnterCriticalSection関数、LeaveCriticalSection関数ではさまれたプログラムは排他制御され他からアクセスされない。 この関数はこんな理解で良いんですかね? この理解で行くと、88章で説明していきますが、子ウィンドウを2つ作成しそれぞれのプロシージャ内で排他制御された関数をスレッドとしてスタートしています。 この2つのスレッドの動作についてですが、互いに排他制御関数が記述されているため、動作としてはまず左の子ウィンドウのスレッドが処理されている場合、右の子ウィンドウのスレッドは停止している。そして左の子ウィンドウのスレッドの排他制御が解放されたときに、右の子ウィンドウのスレッドが開始する。 そしてあるとき左の子ウィンドウのクライアントウィンドウ内で右クリックされた場合、その時点で排他制御されたスレッドが終了するのを待ち、終了したらcountを+1する。 こんな動作が行なわれていると理解してよいのでしょうか?

  • 非同期プログラミングは必ずマルチスレッド?

    非同期プログラミングは必ずマルチスレッドプログラミングになりますか? ここでいう非同期プログラミングとは、 何かのメソッドを実行してその処理(処理Aとする)の結果を待たずに次の処理Bを実行できて、処理Aが終わったらコールバックやデリゲートで、あらかじめ決められたメソッド(finishとする)が呼ばれるといったものです。 処理Aを実行するメソッドを呼ぶ ↓ すぐに処理Bを実行開始(このときバックグラウンドで処理Aが走っている) ↓ 処理Aが終了したのでfinishメソッドが実行される 例えば、Objective-CのNSURLConnectionで非同期通信するときのようなやつです。 こういった非同期プログラミングは、必ずマルチスレッドを使うことになりますか? 普通、別スレッドで処理させるときはスレッド用のライブラリを使うなどして明示的にマルチスレッドプログラミングをしますが、上のように非同期のメソッドを使うと、その裏で自動的に別のスレッドが動くのでしょうか。 それとも、単一スレッドのみで、非同期プログラミングできるでしょうか。 なお、特殊な言語やOSによっては、いくらでも可能性があると思いますので、 メジャーな環境(Windowsや、スマホ) のみに限定してお願いします。言語で言うと、C、C++、Objective-C、Javaあたり。 また、上の「処理A」が終わったとき、メソッド「finish」が呼ばれるとすると、 処理Bの実行中にどのようなタイミングでfinishが呼ばれるのでしょうか。 処理Bはどのような形でfinishに切り替わるのでしょうか。いきなりfinishに処理を奪い取られるのでしょうか

  • [Delphi]入れ子(?)になったプロシージャ

    こんにちは、honiyonです。  あるプロシージャだけが呼び出す関数がある為、次のように定義しました。  procedure Subfunc;   function funcA:integer;   begin    ~    function funcB;    ~   end;   function funcB:integer;   begin    ~    function funcA;    ~   end;  begin   ~  end;  funcAとfuncBは協調して動作するのですが、当然funcAからfuncBは見えていませんので、「funcBが見つからない」とエラーになります。  しかし、この場合どのようにfuncBの存在を定義すれば良いのかわかりません。  あまりこのような形で作成するケースが少ないようで、資料がなく困っています(^^;;  宜しくお願いします(..

  • Delphi for文

    これって、Delphiのバグですか?特性ですか? procedure TForm1.Button1Click(Sender: TObject); begin test(); end; //-------------------------- procedure TForm1.test(); var k,x:integer; begin paintbox1.Canvas.pen.Color:=clBlack ; x:=0; for k:=1 to 3 do begin paintbox1.Canvas.moveto(x,0); paintbox1.Canvas.lineto(x,paintbox1.Height); x:=x+2; end; end; forループ内にブレークポイントを付けて「k」の値の変化を見ると、3,2,1と逆順になります。 「x:=x+2」を「x:=x+k」に変更すると、1,2,3と普通の順になります。 なぜ、こうなるのか? 対処法はありますか? Delphi Ver6・ターボDelphi どちらも同じ状況です。

  • マルチスレッドについて。

    今、大きな配列を元に処理を行うプログラムを作成しています。 シングルスレッドでも十分速度を向上するようチューニングに成功しましたが、マルチスレッド化をすればさらに速度を向上させることができるだろうと考え、先日マルチスレッドかに成功しました。 しかし・・・奇妙な現象が起こりました。 マルチスレッドで性能を引き出すには、排他制御はないほうが良いと考え、メモリは食いますがスレッドに与える入力情報(大きな配列)を2つ用意し、排他制御なしの2スレッドを実行できるようにしました。しかしやはりメモリを消費しすぎてしまうため、配列にアクセスする部分のみ排他制御を行うようクリティカルセクションを設定し入力情報を2スレッドで共有して処理を行うよう組み替えました。 結果、やはり排他制御なしの場合よりはるかにスピードダウンしてしまい、シングルスレッドより少し早い処理時間で終了してしまいました。 余りにも悔しいため、ちょっと危険な実験だとは思いましたが、入力情報を2つのスレッドで共有しているにもかかわらず、排他制御の部分、つまりクリティカルセクションを取り除いて実行してみようと考えました。予想としては同時にアクセスし衝突が起きてエラーで停止してしまうと考えましたが・・・・・・ 結果なぜかエラーなく処理をし続け、普通に終了してしまいました。 これはなぜでしょう? 偶然にも共有情報に同時にアクセスすることがなかったためでしょうか?

  • Androidのマルチスレッド処理の開始タイミング

    組み込みボード上にAndroidOSをのせ、 その上でRS232C通信制御するプログラムを作成しております。 RS232C通信制御についてはThreadクラスを派生させたクラスを 作成し、マルチスレッド処理として、アプリ起動中に、常に動作させたい と考えています。 このとき、RS232C通信制御するスレッドを 開始するタイミング、終了するタイミングはメインアクティビティのどの タイミングで行うのが1番よいのでしょうか? 現状は以下で考えています。 public class MainActivity extends Activity { ComCtrl m_ComCtrl ; // RS232C通信制御スレッド protected void onCreate(Bundle savedInstanceState) { m_ComCtrl = new ComCtrl( null ) ; // スレッド生成 m_ComCtrl.start() ; // スレッド開始 } protected void onDestroy() { m_ComCtrl.halt() ; // スレッド終了(スレッドメインループを終了させる独自メソッド) } }

    • ベストアンサー
    • Java
  • マルチスレッド内のループについて

    こんにちは。 開発環境は VC++6.0 SDI マルチスレッドがあり、2つの処理を行う関数が書かれています。 このスレッドはダイアログボックスに配置したストップボタンを押すとフラグFALSEになりループを終了させます。 2つの関数は、int型の整数を引数にして、処理を行います。 整数はある値に達すると 0 になり永遠にループを続け、2つの処理を行います。 と言う意味合いでプログラムを書きました。(書いたつもりです) (1)この書き方ですと、for内のループが動いている時に、右上の×ボタンでダイアログを閉じると [Debug Assertion Failed!]と言う警告文が出て強制的に終了してしまいます。 ストップボタンを押してもcount=10になるまではループしています。(当然ですが・・。) そもそもマルチスレッドの中にこのような形でfor文を入れるのは間違っているのでしょうか? どのような書き方にすれば良いのでしょうか? よろしくお願い致します。 bool m_flags;//スレッド内の処理を続けるか示すフラグ UINT CabcDlg::thread(LPVOID pParam)// { CabcDlg *pInst = (CabcDlg *) pParam; while(pInst->m_flags){//ストップボタンが押されると終了する。 for (int count = 0; count<10; count++ ) { pInst->OnSend(count); //処理A pInst->OnReceive(count);//処理B } } return 0; }

  • delphi paintbox.invalidate

    ターボdeliphiのPaintBoxです procedure TForm1.Button1Click(Sender: TObject); begin PaintBox1.Invalidate; PaintBox1.Canvas.MoveTo(0,0); PaintBox1.Canvas.lineTo(100,100); end; procedure TForm1.Button2Click(Sender: TObject); begin PaintBox1.Canvas.MoveTo(0,0); PaintBox1.Canvas.lineTo(100,100); end; procedure TForm1.PaintBox1Paint(~~~~~ ボタン1でlineTo(100,100)は描画されず、ボタン2では描画されます。 つまりPaintBox1.Invalidateで再描画させている微妙なタイミングのせいでしょうか? 再描画が終了してからlineTo(100,100)を描画したいのですが、それを知るコマンド?関数?はありますか?

  • マルチスレッド化。

    今とても大きな配列を使用し、長時間処理をするプログラムを組んでいます。元々処理時間に1時間を要するプログラムを2分で処理を完了するまでに仕上げました。 しかし、探究心はおさまらずもう少し高速化に挑みたいと考えています。 過去に「猫でもわかる」のSDK第1章と2章を学び、マルチスレッドのプログラムをSDKで組んだことがあります。それを利用してマルチスレッド化を実現したいと考えています。 言語はCでVisualStudio2005を使用しています。 *疑問1   SDKの場合WinMain関数とプロシージャからの実行で_beginthread関数を記述すれば処理が開始されます。 Cでもmain関数内に記述すれば、SDKと同様に処理できるのでしょうか? *疑問2 _beginthread関数の引数に関してです。 第1引数にvoid型のスレッド関数、第2引数に0?、そして第3引数にはスレッド関数に渡すデータの引数を記述すると把握しているのですが、渡したいデータは複数あり、***型と**型、それに変数を数個とスレッド関数に渡したいデータだらけなのですが、どのように記述すればよいでしょう? *疑問3 2つのスレッドを作成しようと考えていますが、その2つのスレッドで1つの大きな配列を共有して処理したいと考えています。 そのため、スレッド間の同期が必要になるわけですが同期の種類にもクリティカルセクションやミューテックス、イベントと豊富でどれを使用すれば良いのか迷ってしまいます。厳密に同期を取り処理をするにはイベントが一番良いと考えています。 これらの疑問に答えられる方はアドバイスをよろしくお願いします。

  • マルチスレッド[ VB.NET 2005 ]

    VB.NET 2005 VC++で作成した通信DLLをマルチスレッドで呼び出すプログラムを作成しています。 マルチスレッドについてご質問です。 ---------------------------------------------------------------- Private Sub ThreadMethod(ByVal aiIndex As UInt32) fSockInit() ← スレッドスタートなので別スレッドで動く End Sub '************************************************** ' フォームロード '************************************************** Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load wkThread(Index) = New Thread(New ThreadStart(AddressOf ThreadMethod)) wkThread(Index).Start() End Sub '************************************************** ' 接続ボタン押下 '************************************************** Private Sub btConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btConnect.Click fConnect() ← スレッドを指定して動かしたい End Sub '************************************************** ' パラメータ設定ボタン押下 '************************************************** Private Sub btParm_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btParm.Click fParmSet() ← スレッドを指定して動かしたい End Sub ---------------------------------------------------------------- 上記の例では、fSockInitはスレッド別に動作しますが、fConnect、fParmSetはメインスレッドで動作するようになっています。 frmMain_Loadで作成したスレッドを指定(※1)して関数を呼び出すことは出来ないのでしょうか? ※1.「クリックイベント(メインスレッド)→実行するスレッドを指定→関数呼び出し→メインスレッドに戻す」の様に。。。