Uke 13 - Plattformavhengighet, Java-threads/tråder, Docker compose

Oppgaver til mandag 24. - fredag 28. mars

  1. (Oblig) Du kan se følgende inne i den binære koden
    haugerud@data2500:~/c$ xxd a.out
    
    000002a0: 0100 0000 0000 0000 2f6c 6962 3634 2f6c  ......../lib64/l
    000002b0: 642d 6c69 6e75 782d 7838 362d 3634 2e73  d-linux-x86-64.s
    000002c0: 6f2e 3200 0400 0000 1400 0000 0300 0000  o.2.............
    
    
    og koden forventer altså et Linux-operativsystem. Hello.c må kompileres på nytt for at det skal kunne kjøre. a.out kan heller ikke kjøres direkte på en Windows-PC, selvom den også er intel X86. Alle maskinkode må snakke med operativsystemet og a.out-koden prøver å snakke med Linux og blir derfor meget overrasket når den møter Windows. Så i dette tilfellet må programmet kompileres på nytt for å kunne kjøre.
  2. Det finnes en egen JVM (Java Virtual Machine) for hver plattform, Linux og Windows. Dette programmet utfører maskinkode for sin plattform, men begge JVM'ene kan lese samme byte-kode og kjøre den i sitt OS-miljø. Men hvis hovedversjonen av Java er forskjellig, kan det bli et problem. Generelt fungerer ikke class-filer kompilert med nyere versjoner av Java på JVMer med eldre hovedversjonsnummer.
  3. Java og Python er begge plattformuavhengige fordi byte-koden som lages når de kompileres kjørers i en virtuell maskin som dekker over plattformforskjellene. C og C++-program må begge kompileres på nytt på plattformen de skal kjøres på.
  4. (Oblig) Når tre tråder kjører på en CPU får de ca 33% CPU hver, om andre prosesser ikke kjører samtidig. Uansett deler de likt seg i mellom og får ca 1/3 av de tilgjengelige CPU-ressursene hver. ps -L viser at det er 15 threads som kjører (14 hvis programmet bare starter 2). Det er 11 JVM threads, en main-thread og det tre Calc-trådene. Alternativt kan man se det med å taste H i top, eller å taste f i top og så velge number of threads.
  5. (Oblig)

     
    import java.lang.Thread;
    import java.io.PrintStream;

    class CalcThread extends Thread
    {
       static int count = 0;
       int id;
       long res=0;
       
       CalcThread()
            {
             count++;
             id = count;
            }

       public void run()
            {
             System.out.println("Thread nr." + id + " is starting");
             res = work();
            }

       private long work()
            {
           long i,j;
           if(id == 1)
             {
            System.out.println("Thread nr." + id + " calculating");
            for(i = 1;i <= 4000000000L;i++)
              {
                 res += i;
              }
             }
           return(res);
        }
    }

    class Calc
    {
       public static void main(String args[])
       {
          System.out.println("Starts two threads!");
          CalcThread s1 = new CalcThread();
          System.out.println("Thread s1 has id " + s1.id);
          s1.start(); // Allokerer minne og kaller s.run()
          
          CalcThread s2 = new CalcThread();
          System.out.println("Thread s2 has id " + s2.id);
          s2.start();
          System.out.println("s2 started !\n");
          try
        {
           s1.join();
        }
          catch (InterruptedException e)
        {
        }
          
          try
        {
           s2.join();
        }
          catch (InterruptedException e)
        {
        } 
          System.out.printf("Thread nr. 1 calculated %d\n",s1.res);
          System.out.printf("Thread nr. 2 calculated %d\n",s2.res);
       }
    }

     
    import java.lang.Thread;
    import java.io.PrintStream;

    class CalcThread2 extends Thread
    {
       static int count = 0;
       int id;
       long res=0;
       
       CalcThread2()
            {
             count++;
             id = count;
            }

       public void run()
            {
             System.out.println("Thread nr." + id + " is starting");
             res = work();
            }

       private long work()
            {
           long i,j;
           if(id == 1)
             {
            System.out.println("Thread nr." + id + " calculating");
            for(i = 1;i <= 2000000000L;i++)
              {
                 res += i;
              }
             }
           else if(id == 2)
             {
            System.out.println("Thread nr." + id + " calculating");
            for(i = 2000000001L;i <= 4000000000L;i++)
              {
                 res += i;
              }
             }
           return(res);
        }
    }

    class Calc2
    {
       public static void main(String args[])
       {
          long sum;
          System.out.println("Starts two threads!");
          CalcThread2 s1 = new CalcThread2();
          System.out.println("Thread s1 has id " + s1.id);
          s1.start(); // Allokerer minne og kaller s.run()
          
          CalcThread2 s2 = new CalcThread2();
          System.out.println("Thread s2 has id " + s2.id);
          s2.start();
          System.out.println("s2 started !\n");
          try
        {
           s1.join();
        }
          catch (InterruptedException e)
        {
        }
          
          try
        {
           s2.join();
        }
          catch (InterruptedException e)
        {
        } 
          System.out.printf("Thread nr. 1 calculated %d\n",s1.res);
          System.out.printf("Thread nr. 2 calculated %d\n",s2.res);
          sum = s1.res + s2.res;
          System.out.printf("Sum: %d\n",sum);
       }
    }

  6. Å kjøre apt-get clean og dpkg-query er fortsatt nyttig, og også å slette logfiler og lignende som bare finnes på denne containeren. Men det vil ikke spare diskplass å for eksempel fjerne /usr/share/doc/* for dette er en kopi som deles av alle containerene.
  7. Når en tråd blir stoppet, har den verdier i registrene. Disse må bli lagret, akkurat som når en prosess blir stoppet og registrene må lagres. Multiprosessering av tråder er ikke annerledes enn multiprosessering av prosesser, så hver tråd trenger sitt eget område for å lagre registre.
  8. Threads in a process cooperate. They are not hostile to one another. If yield- ing is needed for the good of the application, then a thread will yield. After all, it is usually the same programmer who writes the code for all of them.
  9. User-level threads cannot be preempted by the clock unless the whole process-quantum has been used up. Kernel-level threads can be preempted individually. In the latter case, if a thread runs too long, the clock will interrupt the current process and thus the current thread. The kernel is free to pick a different thread from the same process to run next if it so desires.
  10. Hver tråd kaller sine egne funksjoner/metoder på egenhånd, så den må ha sin egen stack til lokale variabler, retur-adresse etc. Dette gjelder både for user-level tråder og for kernel-level tråder.
  11. version: '3'
    services:
      nginx:
        build: ./nginx
        ports:
          - 8080:80
        volumes:
          - ./innhold:/usr/share/nginx/html:ro
        nginx2:
          image: nginx:latest
          ports:
            - 8081:80
          volumes:
            - ./innhold2:/usr/share/nginx/html:ro
    
    $ cat nginx/Dockerfile
    From nginx:latest
    
    RUN apt-get update -y
    RUN apt install iputils-ping -y
    RUN apt install net-tools -y
    RUN apt install jed -y
    
    
  12. (Oblig)
    version: '3.1'
    services:
      loadbalancer:
          build: ./nginx
          ports:
            - 80:80
      web1:
          image: nginx:latest
          volumes:
            - ./innhold1:/usr/share/nginx/html:ro
      web2:
          image: nginx:latest
          volumes:
            - ./innhold2:/usr/share/nginx/html:ro
    
    Dockerfile
    # cat nginx/Dockerfile
    FROM nginx
    COPY nginx.conf /etc/nginx/conf.d/default.conf
    
  13. (Oblig)