2011-05-19 52 views
12

當Ada應用程序關機/死機時,我想調用一些「清理」調用。Ada關機鉤

舉例來說,如果我是在Java中,我會做這樣的事情,以獲得具有一種叫做在關機的效果:

Runtime.getRuntime().addShutdownHook(new Thread(){ 
     public void run(){ 
      method(); 
     } 
}); 

是否有類似的事情在阿達或另一種方式來實現這一目標?

+2

您的Java示例僅在JVM關閉時調用,而不是程序本身。 – oenone 2011-05-19 06:47:54

回答

7

您可以爲主過程創建一個Controlled(或Limited_Controlled)對象,該過程在其Finalization方法中調用必需的東西。

請注意,您無法訪問主過程的任何局部變量,因此請將任何必需的東西放入受控對象中。

例如:

with Ada.Text_IO; 
with Ada.Finalization; 
procedure Main is 
    type Cleaner is new Ada.Finalization.Limited_Controlled with record 
     Some_Interesting_Data : Integer; 
    end record; 
    overriding procedure Finalize (X : in out Cleaner) is 
    begin 
     Ada.Text_IO.Put_Line ("Cleaning..." & Integer'Image (X.Some_Interesting_Data)); 
    end Finalize; 
    The_Cleaner : Cleaner; 
begin 
    Ada.Text_IO.Put_Line ("Main Procedure."); 
    The_Cleaner.Some_Interesting_Data := 42; 
    Ada.Text_IO.Put_Line ("Finished."); 
end Main; 
+0

不錯!我沒有想到這一點。這一個將立即進入我的小聰明的想法書。謝謝。 – 2011-05-19 07:18:50

+0

我不認爲調用Finalize的順序是指定的,所以如果您使用多個Controlled對象,則不應該依賴該順序。 – oenone 2011-05-19 10:51:45

+0

+1這也是我的第一個想法。我有興趣知道Finalization代碼是否在進程被其他進程終止時運行(例如:Unix'kill -9')。 – 2011-05-19 13:17:58

2

似乎應該有一種方法可以在純Ada中做到這一點,但我找不到一個。

一個想法是使用Interfaces.C並調用atexit()與執行清理的回調函數。我沒有嘗試過,但我想不出任何理由,它不會工作。

More info on Ada callbacks from C

+0

正確,你找不到一個。受控制的類型或故意拋出的異常將爲您完成這項工作。 – NWS 2011-05-19 08:58:41

+1

我懷疑Ada運行時會在退出主程序時結束,這意味着從'atexit()'調用Ada代碼是不正確的。 – 2011-05-19 14:24:41

3

如果它是由用戶或者因爲程序簡單地做了做它發起受控關機,那麼你可以簡單地最後添加調用清除過程。

如果程序因中斷信號而終止,例如發送SIGINT信號的用戶或系統關閉,那麼您可以捕獲這些信號並將清理過程置於註冊的回調中。

我寫了一個關於如何使用Ada捕獲中斷的簡短示例。它可在githubwiki article

另一種選擇是使用來自libre.adacore.com的Florist POSIX包。也許在posix信號包中有一些用處。

10

由於一個阿達主程序作爲任務處理,你可以使用Ada.Task_Termination包來管理執行後的清理工作。在Ada 2005 Rationale中有關於此的一篇文章,下面是一個以演示爲例的快速演示。

你必須提供一個庫一級保護終止程序,所以這裏應該是一個包:

with Ada.Task_Termination; 
with Ada.Task_Identification; 
with Ada.Exceptions; 

package Main_Program_Finalization is 

    protected Shutdown_Handler is 

     procedure Termination_Finalizer 
     (Cause : in Ada.Task_Termination.Cause_Of_Termination; 
     T  : in Ada.Task_Identification.Task_Id; 
     X  : in Ada.Exceptions.Exception_Occurrence); 
    end Shutdown_Handler; 

end Main_Program_Finalization; 

身體:

with Text_IO; use Text_IO; 

package body Main_Program_Finalization is 

    protected body Shutdown_Handler is 

     procedure Termination_Finalizer 
     (Cause : in Ada.Task_Termination.Cause_Of_Termination; 
     T  : in Ada.Task_Identification.Task_Id; 
     X  : in Ada.Exceptions.Exception_Occurrence) 
     is 
     use Ada.Task_Termination; 
     use Ada.Task_Identification; 
     use Ada.Exceptions; 
     begin 
     New_Line; 
     Put_Line("Shutdown information:"); 
     New_Line; 
     case Cause is 
     when Normal => 
      Put_Line("Normal, boring termination"); 
     when Abnormal => 
      Put_Line("Something nasty happened to task "); 
      Put_Line(Image(T)); 
     when Unhandled_Exception => 
      Put_Line("Unhandled exception occurred in task "); 
      Put_Line(Image(T)); 
      Put_Line(Exception_Information(X)); 
     end case; 
     end Termination_Finalizer; 

    end Shutdown_Handler; 

end Main_Program_Finalization; 

主程序(它的成立爲正常終止張貼,取消註釋最後兩行並運行它以查看未處理異常觸發終止的效果):

with Main_Program_Finalization; 
with Ada.Task_Identification; 
with Ada.Task_Termination; 
with Text_IO; use Text_IO; 

procedure task_term is 

    use Ada; 

    Task_ID : Task_Identification.Task_Id 
    := Task_Identification.Current_Task; 

begin 
    Put_Line("Main Task ID: " & Task_Identification.Image(Task_ID)); 

    Put_Line("Setting termination finalizer"); 
    Task_Termination.Set_Specific_Handler 
    (Task_ID, 
     Main_Program_Finalization.Shutdown_Handler.Termination_Finalizer'Access); 
    Put_Line("Go off and do things now..."); 
    delay 1.0; 
    Put_Line("Done with mainline processing, the shutdown handler should now execute"); 

--  Put_Line("Raise an unhandled exception and see what the shutdown handler does"); 
--  raise Constraint_Error; 
end Task_Term; 
+0

我不知道。 JVM通常有一個可用於類似目的的收割線程。 – trashgod 2011-05-19 16:20:39

+0

@trashgod:每當我瀏覽Ada LRM索引的時候,其他一些條目都會引起我的注意。 Task_Termination就是其中之一,因爲導致「部分崩潰」的任務中的未處理異常是我多年前在一個項目中處理的問題,我很高興看到它已被解決。在看到這個問題時,我想起了這個能力,並且研究了在主要計劃任務之後清理是否是一個可行的選擇。它應該是,瞧!所以它是:-) – 2011-05-19 16:43:04

1

如果允許程序很好地關閉,那麼可以使用標準語言工具(如受控類型)來提供「關閉」行爲。

如果程序不允許由操作系統很好地關閉,那麼沒有語言定義的方式來使用任何語言。你將不得不使用某種操作系統調用來做到這一點。

請注意,您展示的示例不是Java調用,而是JVM調用。 JVM = Java虛擬機...實質上是Java OS。假設您的Ada代碼在JVM上運行,您可以從Ada進行完全相同的調用。如果你在Windows下運行,你必須使用Win32系統調用。你可以製作Ada中的那些,但顯然這些確切的調用在語言中是不可移植的。

+0

優秀的一點。作爲Ada和Java的學生,我學會了對一般的「錯誤同源」(http://en.wikipedia.org/wiki/False_cognate)和特別是語言外特性的警惕。 – trashgod 2011-05-19 16:11:44

+0

@trashgod - 是的。 Ada最大的負擔之一是所有的C編碼器似乎認爲每一次操作系統調用都是「C函數」,Java編碼人員似乎認爲整個JVM都是Java語言的一部分。 – 2011-05-19 17:48:06