[ABAP] Timerobjekt cl_gui_timer verwenden

* Hinweis zum Aufruf von cl_gui_timer:
* - selbst mit interval = 1 (1s) triggert der Timer nach run( ) nur alle 2s
* - parallele Listausgaben mehrerer Worker können scheinbar Deadlocks verursachen

* Workerobjekt, welches vom Timer aufgerufen wird
CLASS lcl_worker DEFINITION.
  PUBLIC SECTION.
    METHODS: constructor
      IMPORTING
        i_id TYPE i.
    METHODS: do
      IMPORTING
        i_cnt TYPE i.
    METHODS: finished.

  PRIVATE SECTION.
    DATA: gv_id TYPE i.
ENDCLASS.

CLASS lcl_worker IMPLEMENTATION.
  METHOD constructor.
    gv_id = i_id.
  ENDMETHOD.
  METHOD do.
    WRITE: / 'Do( ) - Timer ID:', gv_id, 'Counter:', i_cnt.
  ENDMETHOD.

  METHOD finished.
    WRITE: / 'Finished( ) - Timer ID:', gv_id.
  ENDMETHOD.
ENDCLASS.

* Timerobjekt, welches zyklisch Worker aufruft
CLASS lcl_timer DEFINITION.
  PUBLIC SECTION.
    METHODS: start
      IMPORTING
        i_worker    TYPE REF TO lcl_worker
        i_interval  TYPE i
        i_count_max TYPE i.

  PRIVATE SECTION.

    DATA: o_worker TYPE REF TO lcl_worker.
    DATA: gv_count_current TYPE i.
    DATA: gv_count_max TYPE i.

    METHODS: on_timer_finished FOR EVENT finished OF cl_gui_timer
      IMPORTING
          sender.
ENDCLASS.

CLASS lcl_timer IMPLEMENTATION.
  METHOD start.
* Übergabewerte ok?
    IF i_count_max >= 0 AND i_interval > 0.
      o_worker = i_worker.

* erster Aufruf -> Funktion sofort ausführen
      o_worker->do( i_cnt = 1 ).

* Zählervariablen setzen
      gv_count_current = 1.
      gv_count_max = i_count_max.

* Timer erzeugen
      DATA(o_timer) = NEW cl_gui_timer( ).
      SET HANDLER on_timer_finished FOR o_timer.
      o_timer->interval = i_interval.
      o_timer->run( ).
    ENDIF.
  ENDMETHOD.

  METHOD on_timer_finished.
* Funktion ausführen
    o_worker->do( i_cnt = gv_count_current + 1 ).

* unendlich
    IF gv_count_max = 0.
* Timer wieder ausführen
      sender->run( ).
    ELSE.
* Anzahl Durchgänge
      gv_count_current = gv_count_current + 1.

      IF gv_count_current < gv_count_max.
* Timer wieder ausführen
        sender->run( ).
      ELSE.
        o_worker->finished( ).
      ENDIF.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

* 1. Timerobjekt mit Worker ID 1
  NEW lcl_timer( )->start( i_worker    = NEW lcl_worker( i_id = 1 )
                           i_interval  = 1
                           i_count_max = 10 ).

* 2. Timerobjekt mit Worker ID 2
  NEW lcl_timer( )->start( i_worker    = NEW lcl_worker( i_id = 2 )
                           i_interval  = 3
                           i_count_max = 5 ).

* 3. Timerobjekt mit Worker ID 3
  NEW lcl_timer( )->start( i_worker    = NEW lcl_worker( i_id = 3 )
                           i_interval  = 2
                           i_count_max = 3 ).

  MESSAGE 'Ok.' TYPE 'S'.