具体来说,有没有办法让任务获得对自身的引用?
例如:
task type someTask;
type someTaskAccessor is access someTask;
task body someTask is
pointerToTask : someTaskAccessor;
begin
pointerToTask = this;
end someTask;
我可以建议的最明显的解决方案是在任务的最开始声明一个集合点(一个条目),您可以将刚刚创建的任务的引用传递给该集合点。另一种可能性是对您的任务类型使用判别式,其作用是告诉新任务它所在的位置(将对新任务的访问传递给判别式)。不幸的是,我手头没有 Ada 编译器,所以我不能给你任何工作示例。
无论如何,根据您的评论:新任务的创建需要在某个地方处理,此时您还需要确定这个新任务将进入您的双向链表的哪个位置(您需要知道至少一个现有任务当创建一个新的以便他们交流时:他们不会神奇地发现自己)。您可以利用这一时刻,当您拥有新创建的任务及其左右对等方时,告诉每个人谁是他们的邻居(再次使用集合点)。
包Ada.Task_Identification提供了 Current_Task 函数来检索当前任务的 Task_ID。
A couple of things here.
First off, Ada does OO differently that C++. There are no "this" pointers in the language. Dispatching is done off of parameters. One implication of this is that it is possible to dispatch off of more than one parameter, unlike in C++. That's another discussion for another time though. If you don't like it, you can always name your dispatching parameter "this".
Secondly, OO concepts don't really apply very well to concurrency objects like tasks. This isn't Ada's fault. It is a well-known problem. Sadly, it was rather unimaginatively termed "The Concurrency Problem", so references to it get swamped with programming issues on a google search. The basic gist is that you can make objects support inheritence and dynamic dispatch and all that good stuff, or you can make them support concurrency. Doing both in the same language structure is very difficult.
As a matter of practicality, if you need a pointer to your own task, you can either make it a global, or have the task that allocates it pass the pointer in using some kind of initilization rendezvous. I've seen this done before, to have a task in a stack of worker tasks put itself back on the "idle" stack when it finishes.
Even though this topic is old I ran across it looking for something similar myself (my need was allowing a task to pass a handle to itself to a protected hash map storage area that all tasks have access to, in affect a registration).
You can do this in Ada 2005, thought it's not recommended because it disables access checks but it's the only way I've found to have a task generate (or find) it's own handle to pass into call back functions (please note this does not preclude Task_ID passing to check for Termination or 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 个任务。还有链表,负责存储任务和管理任务的插入/删除。这是一个应该处理同步的全局对象。
这就是为什么我建议您创建一个受保护的对象,并将任务列表存储在其中。protected 通常用于被动对象,其中某些资源必须同步处理。您可以有插入、删除等过程。这样可以确保一次只运行一个创建和删除,并且链表不会不一致。
每个任务都应该知道它是“伙伴”任务,在插入或删除任务时可能会发生变化。我建议在任务中创建一个条目,该条目将更新其邻居。当任务到来或离开时,受保护对象将更新邻居。
在这种情况下,不需要访问“this”指针,因为受保护的对象会组织一切。只需要一个 ID,它可以识别任务(用于移除)。
I try to write the code, but I do not have compiler now:
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;