Scheduler/Zeitplan zum Ausführen von Befehlen



  • Hallo zusammen,

    Da ich ein kompletter "Neuling" in Sachen c++ bin bräuchte ich etwas Unterstützung. Hänge derzeit ziemlich auf dem Schlauch.

    Ich muss ein Programm schreiben, welches in einem sechs Stundentakt agieren soll. Beispiel: 6:00 Uhr die Verbindung zu einem Server aufbauen, eine Minute später soll ein Befehl zum Ausführen eines Programms geschickt werden. Eine Stunde später folgt der Befehl zum Beenden des Programms und eine Minute später der Befehl zum Beenden der Verbindung. Um 12 Uhr dann das selbe usw..

    Es gibt zwar Anleitungen im Internet wie das gemacht werden könnte, jedoch durchschaue ich die nicht und weiß nicht wo genau ich ansetzen soll. Eventuell gibt es ja leocht zu durchschauende Beispiele von Codeanfang bis -ende zum Ausführen und Beenden eines externen Programms sowie für einen Scheduler/Zeitplan, der beispielsweise um soundsoviel Uhr ein Programm startet und nach einer gewissen Zeit wieder beenden lässt. Diese wurdenir zunächst reichen..

    Bin für jede Hilfe und jeden Tipp dankbar.
    Mfg



  • Ich würde versuchen, die Betriebssystemfunktionen zu nutzen, also geplanter Task oder cron.



  • Morgen Manni,

    danke für die Rückmeldung. An sich würde das natürlich gehen. Das Programm soll aber hier geschrieben werden und dann beim Kunden getestet werden. Mir geht's halt zunächst einmal um ein Programm, das zu den bestimmten Uhrzeiten einen (Licht-)Schalter an macht und jeweils eine Stunde später wieder aus macht, ähnlich wie beschrieben.
    Alles weitere kann dann immer noch nachgetragen werden.

    MfG



  • Du könntest dir einen eigenen Scheduler bauen, das könnte etwa so aussehen:

    #include <memory>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    // Basisklasse für alle konkreten Task-Typen
    class IBasicTask
    {
       bool Finished_ = false;
    
    public:
       IBasicTask() = default;
       virtual ~IBasicTask() = default;
    
       IBasicTask( const IBasicTask& ) = delete;
    
       bool finished() const
       {
          return Finished_;
       }
      
       bool trigger( const Timestamp& timestamp )
       {
          Finished_ = trigger_impl( timestamp );
          return Finished_;
       }
    protected:
       virtual bool trigger_impl( const Timestamp& timestamp ) = 0;
    };
    
    using IBasicTaskPtr_t = std::shared_ptr<IBasicTask>;
    
    // Timed-Task, der zu einem bestimmten Zeitpunkt eine Aktion ausführt
    class TimedTask : public IBasicTask
    {
       Timestamp TimestampDue_;
       // div. andere Eigenschaften, die benötigt werden
    
    public:
       TimedTask( ... );
    
       bool trigger_impl( const Timestamp& timestamp ) override
       {
          if( timestamp >= TimestampDue_ )
          {
             // Aktion ausführen. Gibt true zurück um anzuzeigen, dass 
             // er ausgeführt wurde und damit fertig ist
             run_application( ... );
             return true;
          }
          return false;
       } 
    };
    
    class TaskScheduler 
    {
       std::vector<IBasicTaskPtr_t > Tasks_;
    
       // irgendein asynchroner Mechanismus, der den TaskScheduler regelmäßig anspringt. 
       // Das kann ein Timer, ein Thread oder iwas anderes sein. Wenn es ein Thread ist muss
       // noch darauf geachtet werden, dass enque() und on_driver_tick gegeneinander verriegelt
       // werden müssen um race conditions zu vermeiden (zb. mit einer CriticalSection oder Mutex).
       DriverType                    Driver_;
    
    public:
       TaskScheduler() = default;
    
       void enque( const IBasicTaskPtr_t& task )
       {
          if( task )
          {
             Tasks_.emplace_back( task );
          }
       }
    
       void trigger_tasks()
       {
          const Timestamp timestamp_now = now();
          for( auto& task : Tasks_ )
          {
             task->trigger( timestamp_now );
          }
       }
    
       void remove_finished_tasks()
       {
          auto predicate = []( const IBasicTaskPtr_t& task )
          {
             return task->finished();
          };
          Tasks_.erase( remove_if( Tasks_,begin(), Tasks_.end(), predicate ),
                                   Tasks_.end() );             
       }
       void on_driver_tick()
       {
          // wird in regelmäßigen Abständen vom Driver_ angesprungen
          // Schritt 1: Tasks benachrichtigen 
         trigger_tasks();     
    
          // Schritt 2: fertige Tasks entfernen
          remove_finished_tasks();
       }
    };
    
    int main()
    {
       TaskScheduler tasks;
       tasks.enqueue( make_shared<TimedTask >( "connect to server", Timestamp( 2018, 9, 14, 6, 0, 0 ) );
       tasks.enqueue( make_shared<TimedTask >( "turn on the lights", Timestamp( 2018, 9, 14,  6, 1, 0 ) );
       tasks.enqueue( make_shared<TimedTask >( "turn off the lights", Timestamp( 2018, 9, 14, 7, 1, 0 ) );
       tasks.enqueue( make_shared<TimedTask >( "disconnect from server", Timestamp( 2018, 9, 14, 7, 2, 0 ) );
    
       // Abbruchkriterium für das Programm muss auch noch iwie gepflegt werden
       while( !finished )
       {
         // CPU kurzfristig abgeben um nicht 100% CPU Last zu erzeugen, zB mit Sleep
         Sleep( 10 );
       }
    }
    

    Achtung: Das ist an manchen Stellen nur Pseudo-Code ( zB die Datentypen Timestamp und Driver ) und soll das Prinzip veranschaulichen. Außerdem ist das Beispiel äußerst rudimentär, es werden zB. keine Abhängigkeiten der Tasks untereinander gepflegt oder erneute Ausführungsversuche, wenn ein Task fehlschlägt.



  • Hallo DocShoe,
    vielen Dank dafür. Das ist für einen Laien wie mich natürlich ein "wuchtiger" Code durch den ich nur stellenweise durchblicke. Für Kenner wahrscheinlich Pipifax..Entschuldigung dafür. Ist wahrscheinlich eher für einen gedacht, der sich gut in C++ auskennt also Concept.
    Bei der korrekten Implementation von Timestamp hapert es bei mir leider schon.. Ich glaube am besten wäre es für mich wenn das zunächst nicht mit einem Schalter sondern von mir aus mit einem externen Programm geht (bspw Paint), um die korrekte Funktionsweise zu zeigen.

    MfG



  • Was spricht dagegen die WM_TIMER Nachrichten (OnTimer) mittels SetTimer zu nutzen?

    Wenn man in OnTimer einfach im Minutentakt den Server anfunkt und fragt ob etwas zu machen ist, müsste das doch vollkommen ausreichen.

    Nebenbei hat dann der Server eine Rückmeldung ob der Client noch anwesend ist.

    Ach ja, wenn das Programm für einen Kunden ist und das Ganze übers Netzwerk geht, sollte die Komunikation verschlüsselt ablaufen.
    Und zwar "richtig" verschlüsselt.
    Security by obscurity hilft schon lange nicht mehr.
    XOR, Cäsar (RotX) Verschlüsselungen und andere Bitverschwurbeleien sind keine Verschlüsselungen und halten nicht einmal Script Kiddys davon ab sich mit den digitalen Lichtschaltern zu spielen.

    [EDIT]
    Ich muss gestehen dass ich mich gerne als vortgeschrittener Anfänger bezeichne wenn es ums Programmieren geht.

    Ich lasse von allem meine Finger was mit der Komunikation übers Internet anbelangt.
    Denn da gibt es so viele Fallstricke durch die Angreifer ins Netzwerk einfallen können wesswegen ich diesen Bereich den Profis überlasse.
    [/EDIT]



  • Wow. Wenn der Code da oben schon "wuchtig" ist, dann ist die dir gestellte Aufgabe zu groß für dich. Und zwar um Größenordnungen.



  • Hi,
    danke für die Antworten. Im Prinzip hast du mit dem letzten Beitrag recht, ist zu groß für mich..
    Am besten wäre natürlich jemand, der das für uns realisiert.. Aber auf jeden Fall danke schon mal bis hier hin.

    MfG



  • Natürlich ist das wuchtig, wenn man nicht programmieren/kein C++ kann.
    Aber dir gehts wahrscheinlich eher um eine Hausaufgabe? Ich kann mir schlecht vorstellen, dass jemand, der kaum programmieren kann, richtige Kundenprojekte zu erledigen hat. Außerdem hört sich die Aufgabenstellung für mich an sich schon nach einer Hausaufgabe an.