C# - Threads

JimPanse

Grünschnabel
Hallo zusammen,

bin grad dabei mich in Threads einzuarbeiten und verwende C#-2008.
Zur Gesamtüberlegung dient eine Baustelle mit 1 Chef und 2 Arbeitern. Wie es im wahren Leben nun mal so ist, werden die Aufgaben vom Chef an seinen Arbeitern verteilt. Dabei erhält jeder Arbeiter eine Aufgabe, führt sie aus und melden die Fertigstellung um eine neue Arbeit zu übernehmen. Allerdings gibt es hierbei auch Abhängigkeiten zwischen den einzelnen Aufgaben. Wird eine Abhängigkeit von Aufgabe2 auf Aufgabe1 erstellt, dann darf Aufgabe2, solange Aufgabe1 nicht beendet ist, mit der Ausführung nicht beginnen.

Nun zur groben Programmklärung.
Die Arbeiter sollen in diesem Fall die einzelnen Threads sein. Diese tragen in einer Arrayliste ihren aktuellen Aufgaben-Status (AnzAufgStatus: 1= running, 2=finished, 3=not finished) ein. Damit der Chef den Überblich über seine Arbeiter und deren Aufgaben nicht verliert, werden die einzelnen Threads in einem ThreadArray (executState: 1=Pause, 2=Continue, 3=Stop, 4=TimeOutWaiting, 5=TimeOutExecute) gespeichert. Dabei wird auch gleich überprüft ob die einzelnen Threads beendet sind oder nicht.

Ein Befehl ist wie folgt aufgebaut:
Befehlsliste[X] = " BefehlID : Abhängigkeit : TimeOutWait : TimeOutExecution (tTimeMax) : BefehlName "
Befehlsliste[0] = "1:0:10:20:Befehl 1";
Befehlsliste[1] = "2:1:10:20:Befehl 2"; // Befehl 2 abh. Von Befehl 1

Code:
class Arbeitsmappe
    {
        private int AnzBefehle = 6, AnzArbeiter = 2, NArbeiter, executeState, AnzAufgaben;
        private Thread[] tArray;      
        private int[] AnzAufgabenStatus, tTime, tTimeMax, tStatus;        
        private string[] Befehlsliste;         
        private bool allThreadsFinished;

        public Arbeitsmappe()
        {            
            tArray = new Thread[AnzArbeiter];
            tTime = new int[AnzArbeiter];
            tTimeMax = new int[AnzArbeiter];
            tStatus = new int[AnzArbeiter];
            AnzAufgabenStatus = new int[AnzBefehle];
            Befehlsliste = new string[AnzBefehle];

         // Befehlsliste[X] = " BefehlID : Abh : TimeOutWait : TimeOutExecution (tTimeMax) : BefehlName "
            Befehlsliste[0] = "1:0:10:20:Befehl 1";      // ms=time...*100
            Befehlsliste[1] = "2:1:10:20:Befehl 2";
            Befehlsliste[2] = "3:0:10:20:Befehl 3";
            Befehlsliste[3] = "4:0:10:20:Befehl 4";
            Befehlsliste[4] = "5:0,0:10:20:Befehl 5";
            Befehlsliste[5] = "6:0,0:10:20:Befehl 6";

            Chef();
        }

        private void Chef()
        {
            NArbeiter = 0;
            AnzAufgaben = 0;
            bool written;
            int i, ThreadID = 0;            
      
            while (AnzAufgaben < AnzBefehle)    // LOOP: 
            {                
                if (NArbeiter < AnzArbeiter)
                {
                    lock (this)         // lock(this){wird nicht vom System unterbrochen}
                    {
                        NArbeiter++;    // Laufvariable
                        string[] arg1 = Befehlsliste[AnzAufgaben].Split(new char[] { ':' });
                        Thread tThread = new Thread(ArbeiterFkt);
                        tThread.Name = Befehlsliste[AnzAufgaben];
                     
                     // nach leerem Element suchen, Thread und Timeout eintragen
                        i = 0;
                        written = false;
                        while (written == false)
                        {
                            if (tArray[i] == null)
                            {
                                tArray[i] = tThread;
                                tTimeMax[i] = Convert.ToInt16(arg1[3]);
                                tTime[i] = 0;
                                tStatus[i] = 0;
                                ThreadID = i;
                                written = true;
                            }
                            i++;
                        }
                        AnzAufgabenStatus[AnzAufgaben] = 1;
                        System.Console.WriteLine("1_" + Befehlsliste[AnzAufgaben]);
                        tThread.Start(Befehlsliste[AnzAufgaben] + ":" + ThreadID.ToString());
                        
                        AnzAufgaben++;
                    }
                }
                else
                {
                    Thread.Sleep(100);
                    checkTimeOut();                   
                }
            }
            
         // Überprüfung ob alle Threads beendet sind
            while (allThreadsFinished == false)
            {
                Thread.Sleep(200);
                checkTimeOut();
                allThreadsFinished = true;
                for (i = 0; i < AnzArbeiter; i++)
                {
                    if (tArray[i] != null)
                    {
                        allThreadsFinished = false;
                    }
                }
            }            
            System.Console.WriteLine(executeState);
            System.Console.ReadLine();
        }
     
     // Überprüfung ob Timeout erreicht ist
        private void checkTimeOut()
        {            
            for(int i=0; i<AnzArbeiter; i++)
            {
                if (tArray[i] != null)
                {
                    if (tArray[i].IsAlive)
                    {
                        tTime[i]++;
                        if (tTime[i] > tTimeMax[i])
                        {
                            tStatus[i] = 5;
                            executeState = 5;
                            System.Console.WriteLine("Execution - Timeout: " + tArray[i].Name);
                        }
                    }
                }
            }
        }

        private void ArbeiterFkt(object Befehl)
        {
            int ThreadID, AfgbNr, AfgbTimeWait, AktualWaitingTime=0;
            bool allDependencesFulfilled=false;
            string AnzAufgabenString;
            string[] arg2 = ((string)Befehl).Split(new char[] { ':' });
            string[] AfgbAbh = arg2[1].Split(new char[] { ',' });

            AfgbNr = Convert.ToInt16(arg2[0])-1;
            AfgbTimeWait = Convert.ToInt16(arg2[2]);            
            AnzAufgabenString = arg2[4];
            ThreadID = Convert.ToInt16(arg2[5]);

         // Abhändigkeiten der Befehle untereinander prüfen
            if (Convert.ToInt16(AfgbAbh[0]) != 0)
            {
                while (allDependencesFulfilled == false || tStatus[ThreadID] == 4 || executeState == 4)
                {
                    allDependencesFulfilled = true;
                    for (int i = 0; i < AfgbAbh.Length; i++)
                    {
                        if (AnzAufgabenStatus[Convert.ToInt16(AfgbAbh[i])] != 2)
                        {
                            allDependencesFulfilled = false;
                            Thread.Sleep(100);
                            AktualWaitingTime++;
                            if (AktualWaitingTime > AfgbTimeWait)
                            {
                                tStatus[ThreadID] = 4;
                                executeState = 4;
                                System.Console.WriteLine("Waiting - Timeout: " + tArray[ThreadID].Name);
                            }
                        }
                    }
                }
            }

         // Start, falls die Threadzeit (TimeOut) nicht abgelaufen
            if (tStatus[ThreadID] != 4 && executeState != 4)
            {
             // Ausführung Start
                for (int i = 0; i < 20; i++)
                {
                    Thread.Sleep(100);
                }
                AnzAufgabenStatus[AfgbNr] = 2;
                System.Console.WriteLine("2_" + Befehlsliste[AfgbNr]);
            }
            else
            {
                AnzAufgabenStatus[AfgbNr] = 3;
                System.Console.WriteLine("3_" + Befehlsliste[AfgbNr]);
            }
            tArray[ThreadID] = null;
            NArbeiter--;            
        }
    }

Nun zu meinem Problem.
Die Abhängigkeiten funktionieren noch nicht so richtig. Momentan (siehe Code) ist Befehl2 von Befehl1 abhängig. Das Programm läuft durch, startet alle einzelnen Befehle und beendet diese bis auf dem, dem man die Abhängigkeit erteilt hat. In diesem Fall wird Befehl2 nicht beendet.
Ab einfachsten ist es wenn man den Code in einer „Konsolenanwendung“ portiert und startet. Dabei kann man sich einfacher meine Problemstellung vorstellen. Zum Testen reichte es wenn man im Befehl an zweiter Stelle (Abhängigkeit) die Zahl ändert.

Vielleicht könnt ihr mir dabei helfen.
Über mögliche Ideen würde ich mich freuen.

Vielen Dank schon mal
 
Zurück