代码之家  ›  专栏  ›  技术社区  ›  ArthurTheLearner

中止Ada中使用重新排队的受保护对象的进程

  •  4
  • ArthurTheLearner  · 技术社区  · 12 年前

    我的程序遇到了一些问题。

    我有一个进程,它调用一个函数(Take_Job),该函数在经过一段时间(MINIMUM_WAIT)之前应该保持阻塞状态。如果不以这种方式发生,则会显示一条消息,告知此情况。

    for Printer_Id in Type_Printer_Id loop
       select
          delay MINIMUM_WAIT
          Pragma_Assert (True, "");
       then abort
          Take_Job (Controller,
                         Printer_Id,
                         Max_Tonner,
                         Job,
                         Change_Tonner);
          Pragma_Assert
            (False,
               "Testing of Take_Job hasn't been successful. It should have remained blocked.");
       end select;
    end loop;
    

    Take_Job函数调用受保护对象中的条目:

    procedure Take_Job (R                 : in out Controller_Type;
                             Printer      : in     Type_Printer_Id;
                             Siz          : in     Typo_Volume;
                             Job          :    out Typo_Job;
                             Excep_Tonner :    out Boolean) is
    begin
       R.Take_Job(Printer, Siz, Job, Excep_Tonner);
    end Take_Job;
    

    其中“R”是受保护对象。

    以下代码是受保护对象的条目。实际上,“when”条件为True,因为我需要检查条目的参数。由于Ada不允许我这样做,我复制受保护对象内的参数并调用“延迟条目”,然后在“延迟条目中”,我将确保在继续之前满足条件。

    entry Take_Job(Printer_Id: in Type_Printer_Id; Remaining: in Type_Volume; Job: out Type_Job; exceptionTonner: out Boolean)
    when True is
    begin
       Copy_Remaining(Printer_Id) := Remaining;
       requeue Take_Job_Delayed(Printer_Id);
    end Take_Job;
    

    让我们看看“延迟进入”代码:

    entry Take_Job_Delayed(for J in Type_Printer_Id)(Printer_Id: in Type_Printer_Id; Remaining: in Type_Volume; Job: out Type_Job; exceptionTonner: out Boolean)
    when False is -- I've done this on purpose
    begin
       null; -- Actually, there would be a lot of code here
    end Take_Job_Delayed;
    

    假设我的目标是通过MINIMUM_WAIT并运行“Pragma_Assert(True,“)”。如果我将Take_Job的“when”条件设置为“False”,那么一切都正常。Take_Job永远不会被接受,Pragma_Assert将被执行。如果我将其设置为“True”,将Take_Job_Delated的“when”条件设置为“False”,则不会得到相同的效果,并且进程会被阻止,并且不会执行任何Pragma_Assert。

    为什么?看起来问题出在“重新排队”或附近,但为什么会发生这种情况?

    1 回复  |  直到 12 年前
        1
  •  5
  •   Simon Wright    12 年前

    你需要重新排队 with abort ;

    entry Take_Job(Printer_Id: in Type_Printer_Id;
                   Remaining: in Type_Volume;
                   Job: out Type_Job;
                   exceptionTonner: out Boolean)
    when True is
    begin
       Copy_Remaining(Printer_Id) := Remaining;
       requeue Take_Job_Delayed(Printer_Id) with abort;
    end Take_Job;
    

    因为否则中止进入呼叫的机会已经丢失。有关详细信息,请参阅 ARM 9.5.4 ,以及Burns&Wellings公司, “Concurrency in Ada” .