45
William Sandqvist [email protected] Övning 9 Trådar och Semaforer

William Sandqvist [email protected] Övning 9 Trådar och Semaforer

Embed Size (px)

Citation preview

Page 1: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Övning 9

Trådar och Semaforer

Page 2: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Digitala komponenter

Assemblerprogram

C

In- och utmatning

Avbrott och "trap"

Cacheminnen

Trådar, synkronisering

DC F1

DC F2

CE F1

CE F3

CE F4

CE F5

CE F6

CE F7

CE F8

CE F9

CE F10

CE F2

DC Ö1

DC Ö2

CE Ö4

CE Ö1

CE Ö2

CE Ö3

CE Ö10

CE Ö7

CE Ö8

CE Ö9

CE Ö5 CE Ö6

lab dicom

lab nios2time

hemlab C

lab nios2io

lab nios2int

hemlab cache

hemlab trådar

tentamen

Datorteknik & komponenter

Page 3: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Kommer ni ihåg: Reella talDecimalkomma ”,” och Binärpunkt ”.”

10,312510 = 1010.01012

Page 4: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

IEEE – 32 bit float

Dec IEEE-754

Genom att exponenteten skrivs exess–127 kan flyttal storlekssorteras med vanlig heltalsaritmetik!

Page 5: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

9.1 MaskinaritmetikIEEE 32 bit flyttal

s eeeeeeee fffffffffffffffffffffff31 30 23 22 0

4 0 C 8 0 0 0 0 01000000110010000000000000000000

Vad blir:

+1,562522 = +6,25

0 10000001 10010000000000000000000

+ 129-127 1 + 0.5+0.0625

Page 6: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

http://babbage.cs.qc.cuny.edu/IEEE-754/32bit.html

Page 7: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Programvaran till Hemlab 3

Page 8: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Allt kan inte skrivas i C.

Med C kan man inte nå namngivna register (register betyder bara en rekommendation att använda något register)

Med C kan man inte styra vilken instruktion som ska användas

Med C kan man inte styra var i minnessegmenten variabler placeras (men man kan använda adress-operatorn & för att undersöka var variablerna hamnar)

Page 9: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

(Primtal är bra testverktyg)Räkna primtal. En algoritm som prövar talen i ordning och ”producerar” primtalen är en bra ”pseudoslump”-generator. Primtalstätheten minskar ju större tal man undersöker, så med startvärdet kan man styra hur ofta primtal-en skall produceras. (Primtalskunskap ingår naturligtvis inte i kursen).

Page 10: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Producer/Consumer (primtal)

Page 11: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Timesharing, trådar delar på en CPU

Page 12: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Timeravbrott och trådbyte

Page 13: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Timer_1 tick

# Initialize timer_1. movia r8,de2_timer_1_base movia r9,de2_timer_1_timeout_value srli r10,r9,16 stw r10,12(r8) # Write periodh andi r10,r9,0xffff stw r10,8(r8) # Write periodl movi r10,7 # start, cont, ito stw r10,4(r8)

oslab_lowlevel_asm.s

Var har Du sett det här förut?

Page 14: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Yield (trap-instruktion) och trådbyte

Page 15: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

oslab_yield()Trap-instruktionen kan man man inte nå från C.Därför gör man en assemblerfunktion med trap-instruktionen att anropa från C (”Wrapper”, ett paket).

.global oslab_yieldoslab_yield: trap ret

void oslab_yield( void);

oslab_lowlevel_asm.s

Page 16: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

oslab_begin_critical_region()

Disable interrupt, nollställa PIE-biten i status-registret, kan man man inte nå från C. Därför gör man en assemblerfunktion att anropa från C (”Wrapper”, ett paket).

.global oslab_begin_critical_regionoslab_begin_critical_region: wrctl status,r0 ret

void oslab_begin_critical_region( void);

oslab_lowlevel_asm.s

Page 17: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

oslab_end_critical_region()

Enable interrupt, ettställa PIE-biten i status-registret, kan man man inte nå från C. Därför gör man en assemblerfunktion att anropa från C (”Wrapper”, ett paket).

.global oslab_end_critical_regionoslab_end_critical_region: movi r8,1 wrctl status,r8 ret

void oslab_end_critical_region( void);

oslab_lowlevel_asm.s

Page 18: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

oslab_exeption_handler

timeslices yield

oslab_lowlevel_asm.s

Page 19: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

oslab_exeption_handleroslab_exception_handler: rdctl et,estatus # Check ESTATUS andi et,et,1 # Test EPIE beq et,r0,oslab_exception_was_not_an_interrupt rdctl et,ipending # Check IPENDING beq et,r0,oslab_exception_was_not_an_interrupt

# If control comes here, we have established that the # exception was caused by an interrupt. # Possible source Timer_1 . . .oslab_exception_was_not_an_interrupt: # Possible source trap-instruction (YIELD) . . .

Var har Du sett det här förut?

oslab_lowlevel_asm.s

Page 20: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Trådarnas kod, data, och stack

Page 21: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Trådarnas data och stack#include <stdio.h>#include "oslab_lowlevel_h.h" int NextPrime( int );#define FIFO_SIZE 10

struct Prod { int startvalue; int id;};

unsigned int stack1[0x400]; /* Stack for thread 1 */unsigned int stack2[0x400]; /* Stack for thread 2 */unsigned int stack3[0x400]; /* Stack for thread 3 */unsigned int stack4[0x400]; /* Stack for thread 4 */unsigned int stack5[0x400]; /* Stack for thread 5 */

oslab_main.c

Varje tråd har en egen stack

Trådarna har egna dataposter (struct)

Page 22: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Fifo-kö, och semaforeroslab_main.c

int Fifo[FIFO_SIZE]; /* Array holding FIFO queue data. */int rdaddr; /* Next unread entry when reading from queue. */int wraddr; /* Next free entry when writing into queue. */

/* Declaration of semaphore variables. */int rdmutex = 1;int wrmutex = 1;int nrempty = FIFO_SIZE;int nrfull = 0; Räknande semaforer

Binära semaforer

Page 23: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

PutFifo() GetFifo()void PutFifo( int tal ){ Fifo[wraddr] = tal; /* Write to FIFO array. */ wraddr = wraddr + 1; /* Increase FIFO array index */ /* point to free position. */ /* Wrap around if index has reached end of the array. */ if (wraddr == FIFO_SIZE ) wraddr = 0;}

int GetFifo( void ){ int retval; /* Declare temporary for return value. */ retval = Fifo[rdaddr]; /* Get value from FIFO array. */ rdaddr = rdaddr + 1; /* Increase FIFO array index */ /* point to free position. *//* Wrap around if index has reached end of the array. */ if (rdaddr == FIFO_SIZE ) rdaddr = 0; return (retval); /* Return value fetched from FIFO. */}

oslab_main.c

Page 24: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Fifo - figur

FIFO_SIZE = FifoEnd - Fifo

Page 25: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Fifon en gemensam resurs

Riskabelt med trådbyte mellan producers precis när en tråd gör PutFifo()

wraddr kan bli fel!

Riskabelt med trådbyte mellan consumers precis när en tråd gör GetFifo()

rdaddr kan bli fel!

Page 26: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Skydda Fifon med semaforer

wrmutex

nrempty

rdmutex

nrfull

Page 27: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Signal()/* * Signal * Semaphore operation: add to semaphore, * possibly allowing other threads to continue. */void Signal( int *sem ){ /* We must disable interrupts, since the operation * *sem = *sem + 1 * will require several machine instructions. * If we have a timer-interrupt and a thread-switch * the semaphore will be updated twice, * or not at all, or in some other erroneous way. */ oslab_begin_critical_region(); *sem = *sem + 1; oslab_end_critical_region();}

oslab_main.c

Page 28: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Wait()/* * Wait * Sempahore operation: check semaphore, and * wait if the semaphore value is zero or less. */void Wait( int *sem ){ /* Disable interrupts */ oslab_begin_critical_region(); while ( *sem <= 0 ) { /* If wait, enable interrupts again. */ oslab_end_critical_region(); //oslab_yield(); /* Perhaps yield here? */ /* Disable interrupts before loop. */ oslab_begin_critical_region(); } /* Semaphore is now greater than zero */ *sem = *sem - 1; /* Enable interrupts again */ oslab_end_critical_region();}

oslab_main.c

Page 29: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Skydda PutFifo() med semaforer

void PutFifo( int tal ){ Wait (&nrempty); /* Wait for nrempty */ Wait (&wrmutex); /* Wait for wrmutex */ Fifo[wraddr] = tal; /* Write to FIFO array */ wraddr = wraddr + 1; /* index to next free */ /* Wrap around the index if reached the end */ if (wraddr == FIFO_SIZE ) wraddr = 0; Signal (&wrmutex); /* Signal wrmutex */ Signal (&nrfull); /* Signal nrfull */}

oslab_main.c

Page 30: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Skydda GetFifo() med semaforerint GetFifo( void ){ int retval; /* temporary for return value */ Wait (&nrfull); /* Wait for nrfull */ Wait (&rdmutex); /* Wait for rdmutex */ retval = Fifo[rdaddr]; /* Get value from FIFO */ rdaddr = rdaddr + 1; /* Increase FIFO index */ /* Wrap around the index if reached the end */ if (rdaddr == FIFO_SIZE ) rdaddr = 0; Signal (&rdmutex); /* Signal rdmutex */ Signal (&nrempty); /* Signal nrempty */ return retval; /* Return value from FIFO. */}

oslab_main.c

Page 31: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Page 32: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Producer()oslab_main.c

void Producer( struct Prod * prodstruct ){ int next; /* to hold the prime just produced */ int prodid; /* Producer 1, 2 or 3 */ next = prodstruct -> startvalue; /* Get startvalue */ prodid = prodstruct -> id; /* Get producer number */ while( 1 ) /* Loop forever */ { next = NextPrime (next); /* Produce a new prime */ printf("Prime from P %d is %d", prodid, next); PutFifo(next); /* Write prime into FIFO. */ //oslab_yield(); /* Try to yield here? */ }}

Page 33: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Consumer()oslab_main.c

void Consumer( int * tal ){ int next; /* to hold the prime to consume */ int consid = *tal; /* Consumer 1 or 2 */

while( 1 ) /* Loop forever */ { next = GetFifo(); /* Get new prime from FIFO */ printf(”C %d gets prime %d", consid, next); Sleep(2000); /* Symbolic work */ //oslab_yield(); /* Try to yield here? */ }}

Page 34: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

main()oslab_main.c

int main( void ){ int tid1, tid2, tid3, tid4, tid5; /* for Thread ID */ struct Prod prod1, prod2, prod3; /* P context */ int cons1, cons2; /* C context */ rdaddr = 0; /* FIFO initialization */ wraddr = 0; /* FIFO initialization */ printf("System starting..."); prod1.startvalue = 2000; prod1.id = 1; prod2.startvalue = 5000; prod2.id = 2; prod3.startvalue = 8000; prod3.id = 3; cons1 = 1; cons2 = 2; . . .

Page 35: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Starta tråd …oslab_main.c

tid1 = oslab_create_thread((void *)Producer,&prod1,&(stack1[0x3ff]));printf("Producer %d is created with thread-ID %d",prod1.id, tid1);

/*Change this comment to start threads! tid2 = oslab_create_thread((void *)Producer,&prod2,&(stack2[0x3ff])); printf("Producer %d is created with thread-ID %d",prod2.id, tid2); tid3 = oslab_create_thread((void *)Producer,&prod3,&(stack3[0x3ff])); printf("Producer %d is created with thread-ID %d",prod3.id, tid3); tid4 = oslab_create_thread((void *)Consumer, &cons1,&(stack4[0x3ff])); printf(”Consumer %d is created with thread-ID %d",cons1, tid4); tid5 = oslab_create_thread((void *)Consumer,&cons2,&(stack5[0x3ff])); printf(”Consumer %d is created with thread-ID %d",cons2, tid5);/* End of comment. */oslab_idle(); /* Must be called here! */}

Page 36: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Starta fler trådar …oslab_main.c

tid1 = oslab_create_thread((void *)Producer,&prod1,&(stack1[0x3ff]));printf("Producer %d is created with thread-ID %d",prod1.id, tid1);

/*Change this comment to start threads! */ tid2 = oslab_create_thread((void *)Producer,&prod2,&(stack2[0x3ff])); printf("Producer %d is created with thread-ID %d",prod2.id, tid2);/*tid3 = oslab_create_thread((void *)Producer,&prod3,&(stack3[0x3ff])); printf("Producer %d is created with thread-ID %d",prod3.id, tid3); tid4 = oslab_create_thread((void *)Consumer, &cons1,&(stack4[0x3ff])); printf(”Consumer %d is created with thread-ID %d",cons1, tid4); tid5 = oslab_create_thread((void *)Consumer,&cons2,&(stack5[0x3ff])); printf(”Consumer %d is created with thread-ID %d",cons2, tid5);/* End of comment. */oslab_idle(); /* Must be called here! */}

Page 37: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Trådbytet

Page 38: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Trådbytet i detalj

Page 39: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Registeranvändning

Page 40: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Post om 27 Ord på stacken.

Page 41: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

(3) Registerinnehåll sparasoslab_lowlevel_asm.s

# Save registers r1 through r23, plus fp, gp, ra and ea subi sp,sp,108 # Make room for all registers. stw r1,4(sp) # R1 is saved in slot 1, not slot 0 stw r2,8(sp) stw r3,12(sp) . . . stw r10,40(sp) stw r11,44(sp) . . . stw r23,92(sp) stw r26,96(sp) stw r28,100(sp) stw r31,104(sp) stw ea,0(sp) # Special case, saved in slot 0 mov r4,sp # Copy stack pointer to R4 movia sp,oslab_system_stacktop # Use system stack

Indexerad adressering används i stället för PUSH. Detta sparar 50% instruktioner!

Page 42: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

(4) oslab_internal_threadswitchoslab_lowlevel_c.c

movia et, oslab_internal_threadswitchcallr et # call C thread switch function

unsigned intoslab_internal_threadswitch( unsigned int old_sp ){ unsigned int new_sp; /* Save the stack pointer of the old thread. */ . . . /* Perform the scheduling decision (round-robin) */ oslab_running_thread += 1; if( oslab_running_thread >= oslab_current_thread_count ) oslab_running_thread = 0;

/* Get the stack pointer of the new thread */ . . . return new_sp ;

}

Page 43: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

(5) Registerinnehåll återställsoslab_lowlevel_asm.s

mov sp,r2 # Copy return value to stack pointerldw r1,4(sp) # restore registers ldw r2,8(sp)ldw r3,12(sp)ldw r4,16(sp)ldw r5,20(sp)ldw r6,24(sp) . . .ldw r23,92(sp)ldw r26,96(sp)ldw r28,100(sp)ldw r31,104(sp)ldw ea,0(sp) # Special caseaddi sp,sp,108eret # Return from exception

Indexerad adressering används i stället för POP. Detta sparar 50% instruktioner!

Page 44: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

os_lab_create_thread()oslab_lowlevel_c.c

int oslab_create_thread( int (*thread_function)(void *), void * thread_arg, unsigned int * thread_stack )

En ny tråd skapas med det stackinnehåll som den skulle haft om den blivit avbruten från början …

unsigned int * new_thread_sp = thread_stack - 27;for( i = 1; i < 24; i += 1 ) new_thread_sp[ i ] = 0;new_thread_sp[ 24 ] = (unsigned int) oslab_internal_get_gp();new_thread_sp[ 25 ] = 0;new_thread_sp[ 26 ] = (unsigned int) oslab_exit_thread;new_thread_sp[ 0 ] = (unsigned int) thread_function;new_thread_sp[ 4 ] = (unsigned int) thread_arg;

Post med 27 ordpå stacken.

Page 45: William Sandqvist william@kth.se Övning 9 Trådar och Semaforer

William Sandqvist [email protected]

Ex. Fördelning av CPU-tid

FIFO har 10 platser Wait utan Yield

Kapacitet: P 4 st, C 8 st