質問
具体的には、自分自身への参照を取得するタスクのための方法は何ですか?
例
task type someTask;
type someTaskAccessor is access someTask;
task body someTask is
pointerToTask : someTaskAccessor;
begin
pointerToTask = this;
end someTask;
解決
私が提案する可能性が最も明白な解決策は、先ほど作成したタスクへの参照を渡すために、あなたのタスクの先頭にランデブー(エントリー)を宣言することです。他の可能性は、その役割は、それが配置されている新しいタスクを伝えることです、あなたのタスクタイプに判別式を使用している(判別式に新しいタスクへのアクセスを渡します)。私はあなたにすべての作業例を与えることができないので、残念ながら、私は手元にエイダのコンパイラを持っていません。
とにかく、あなたのコメントに基づいて:新しいタスクの作成はどこかに処理する必要があり、あなたも、この新しいタスクは、あなたの二重リンクリストに入ります場所を決定する必要があります、その時点で(あなたは、少なくとも知っている必要があります1つの既存のタスクそれらが通信するために新しいものを作る:彼らは魔法のように自分自身を発見しません)。あなたが新たに作成されたタスクとその左右のピアを持っているとき、あなたは(もう一度ランデブーを使用して)彼らの隣人です皆に伝えるために、この瞬間を活用することができます。
他のヒント
パッケージ Ada.Task_Identificationする現在のタスクのTASK_IDを取得するためにCurrent_Task機能を提供しています。
ここでは物事のカップルます。
まず第一に、エイダは、C ++という異なっOOを行います。言語には「この」ポインタはありません。派遣は、パラメータのオフに実行されます。これの一の含意は、C ++とは異なり、複数のパラメータのオフに派遣することが可能であるということです。それはしかし、別の時間のために別の議論です。あなたがそれを気に入らない場合は、常に「これを」あなたのディスパッチパラメータに名前を付けることができます。
第二に、オブジェクト指向の概念は、本当に仕事のような並行処理オブジェクトに非常によく適用されません。これは、エイダの故障ではありません。これはよく知られた問題です。悲しいことに、それはむしろunimaginatively「同時実行性の問題」と呼ばれたので、それへの参照は、Google検索でのプログラミングの問題が殺到ます。基本的な要点は、あなたがオブジェクトが継承し、動的ディスパッチとすべてが良いものをサポートすることができ、またはあなたがそれらを同時実行をサポートして作ることができるということです。両方とも同じ言語構造で行うことは非常に困難である。
あなたがあなた自身の仕事へのポインタが必要な場合は、は、実用性の問題として、あなたはそれがグローバルに、またはそれがinitilizationランデブーのいくつかの種類を使用してポインタを渡し割り当てタスクを持つことができます。私はそれが終了すると、スタック「アイドル」に自分自身を戻す作業員のタスクのスタック内のタスクを持っている、これは前に行って見てきます。
(私の必要性は、タスクはすべてのタスクがで登録に影響を与え、へのアクセス権を持っていることを保護されたハッシュマップの記憶領域に自分自身へのハンドルを渡すことができました)ます。
あなたはエイダ2005年にこれを行うことができ、(注意してくださいコールバック関数に渡すために、それ自身のハンドルにはアクセスチェックを無効にしますが、それは、私はタスクが発生する(または見つける。)有することが判明してきた唯一の方法だからそれはお勧めしませんと思いましたこれはTASK_IDが終了またはIs_Callable)をチェックするために渡して排除するものではありません。
task type someTask;
type someTaskAccessor is access someTask;
task body someTask is
-- Initialize the access type variable as pointing to the same task it's declared in.
pointerToTask : someTaskAccessor := someTask'Unchecked_Access; --equiv to "this" ptr
begin
-- pointerToTask = this; --this is unneeded, pointerToTask is already set!
end someTask;
私はあなたのコードを再編成します。だから、今2つのタスクを他のタスクと対話するいくつかのタスクがあります。そして、タスクを格納し、タスクの挿入/削除を管理する責任があるリンクリストは、そこにあります。これは、同期処理するグローバルオブジェクトです。
私はあなたが保護されたオブジェクトを作成するためのアドバイス、およびその内部のタスクのリストを保存する理由です。保護は、典型的には、いくつかのリソースを扱う同期させなければならないパッシブオブジェクトのために使用されています。あなたは、これが唯一の作成と削除が同時に実行されることを保証します、とリンクリストは矛盾ではありません、挿入のような手順を持っているなどを削除することができます。
それぞれのタスクは、それが挿入またはタスクの削除変更することができ、「パートナー」タスクを知っている必要があります。私はその隣人を更新するタスクへのエントリを作成しますアドバイス。タスクが来るか去るときに、保護されたオブジェクトは、隣人を更新します。
この場合には、保護されたオブジェクトはすべてを整理しますので、「この」ポインタにアクセスする必要はありません。唯一のIDを(除去する)タスクを識別することができ、必要とされている。
私は、コードを書いてみるが、私は今のコンパイラを持っていません。
task type computer;
type computer_ptr is access all computer;
task type computer is
entry init(id:integer);
entry set_neighbor(left,right:computer_ptr);
end computer;
protected comp_list is
procedure insert; -- called by organizer
procedure remove(from:integer); -- called by task
private
type comp_list is array(integer range<>) of computer_ptr;
comps:comp_list(1..MAX):=(others=>null); -- or use own structure
end comp_list;
task body computer is
id_:integer;
left_n,right_n:computer_ptr:=null;
begin
accept init(id:integer) do
id_:=id;
end init;
while true loop
select
accept set_neighbor(left,right:computer_ptr) do
left_n:=left;right_n:=right;
end set_neighbor;
or
-- do its work
end select;
if (some_condition) then
comp_list.remove(id_);
break;
end if;
end loop;
end task computer;
protected body comp_list is
procedure insert is
p:computer_ptr;
begin
p:=new computer;
-- add to list -> nr;
p.all.init(nr);
-- call set_neighbor to its left and itself
end insert;
procedure remove(from: integer) is
begin
-- remove from list and get its neighbors
-- call set_neighbor regarding new ones
end remove;
end comp_list;