Есть ли в Ada ключевое слово this? - PullRequest
3 голосов
/ 31 октября 2009

В частности, есть ли у задачи способ получить ссылку на себя?

Например:

task type someTask; 
type someTaskAccessor is access someTask;

task body someTask is
    pointerToTask : someTaskAccessor;
begin
    pointerToTask = this;
end someTask;

Ответы [ 5 ]

4 голосов
/ 02 ноября 2009

самое очевидное решение, которое я мог бы предложить, это объявить рандеву (запись) в самом начале вашей задачи, к которой вы передаете ссылку на только что созданную задачу. другая возможность - использовать дискриминант для вашего типа задачи, роль которого заключается в сообщении новой задаче, где она находится (передать доступ к новой задаче в дискриминант). к сожалению, у меня нет под рукой компилятора Ada, поэтому я не могу привести вам ни одного рабочего примера.

в любом случае, основываясь на вашем комментарии: создание новой задачи должно быть где-то обработано, после чего вам также нужно будет определить, куда эта новая задача войдет в ваш список с двумя связями (вам нужно знать, по крайней мере, одна существующая задача при создании новой, чтобы они могли общаться: они не обнаружат себя волшебным образом). Вы можете воспользоваться этим моментом, когда у вас есть только что созданное задание и его левый и правый одноранговые узлы, чтобы рассказать всем, кто является их соседом (еще раз с помощью рандеву).

4 голосов
/ 01 ноября 2009

Пакет Ada.Task_Identification предоставляет функцию Current_Task для получения идентификатора задачи текущего задания.

1 голос
/ 05 октября 2013

Несмотря на то, что эта тема старая, я сам наткнулся на нее в поисках чего-то похожего (мне нужно было разрешить задаче передать себе дескриптор в защищенную область хранения хэш-карт, к которой имеют доступ все задачи, влияющие на регистрацию) .

Вы можете сделать это в Ada 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;
1 голос
/ 12 ноября 2009

Несколько вещей здесь.

Во-первых, Ада делает ОО иначе, чем С ++. На этом языке нет указателей «это». Диспетчеризация осуществляется из параметров. Одним из следствий этого является то, что в отличие от C ++ возможно отправить более одного параметра. Это еще одно обсуждение в другое время, хотя. Если вам это не нравится, вы всегда можете назвать свой диспетчерский параметр "this".

Во-вторых, концепции ОО не очень хорошо применимы к объектам параллелизма, таким как задачи. Это не вина Ады. Это известная проблема. К сожалению, это было довольно невообразимо названо «Проблема параллелизма», поэтому ссылки на него завалены проблемами программирования в поиске Google. Основная суть в том, что вы можете заставить объекты поддерживать наследование и динамическую диспетчеризацию и все такое хорошее, или вы можете заставить их поддерживать параллелизм. Делать и то, и другое на одной языковой структуре очень сложно.

С практической точки зрения, если вам нужен указатель на вашу собственную задачу, вы можете либо сделать его глобальным, либо поручить задаче, которая его выделяет, передать указатель, используя какое-то рандеву инициализации. Я видел, как это было сделано ранее, чтобы задача в стеке рабочих задач возвращалась в стек «ожидания» после завершения.

0 голосов
/ 11 ноября 2009

Я бы реорганизовал твой код на твоем месте. Итак, есть некоторые задачи, которые взаимодействуют с другими задачами, теперь с 2 задачами. И есть связанный список, который отвечает за хранение задач и управляет вставкой / удалением задач. Это глобальный объект, который должен обрабатывать синхронизированный.

Вот почему я советую вам создать защищенный объект и сохранить в нем список задач. Защищенный типично используется для пассивных объектов, где некоторый ресурс должен обрабатываться синхронно. У вас могут быть такие процедуры, как вставка, удаление и т. Д. Это гарантирует, что одновременно будет выполняться только одно создание и удаление, а связанный список не будет противоречивым.

Каждая задача должна знать, что это «партнерские» задачи, которые могут измениться при вставке или удалении задачи. Я советую создать запись в задаче, которая обновит его соседей. Когда задачи приходят или уходят, защищенный объект обновляет соседей.

В этом случае нет необходимости обращаться к указателю «this», потому что защищенный объект организует все. Требуется только идентификатор, который может идентифицировать задачу (для удаления).

Я пытаюсь написать код, но у меня сейчас нет компилятора:

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;
...