├── .gitattributes ├── Info ├── JMP.pdf ├── CMP & Flags.pdf ├── Comparison.pdf ├── Conditional Jump.pdf ├── Conditional Jumps After CMP.md ├── Comparison.md ├── CMP & Flags.md └── Conditional Jump.md ├── Lab 1 - Exercises.pdf ├── Lab 2 - Exercises.pdf ├── Lab 3 - Exercises.pdf ├── Lab 4 - Exercises.pdf ├── Lab 5 - Exercises.pdf ├── Lab 03 ├── Ex_20.asm ├── Ex_27.asm ├── Ex_26.asm ├── Ex_21.asm ├── Ex_19.asm ├── Ex_24.asm ├── Ex_18.asm ├── Ex_23.asm ├── Ex_22.asm ├── Ex_12.asm ├── Ex_25.asm ├── Ex_16.asm ├── Ex_13.asm ├── Ex_15.asm ├── Ex_17.asm └── Ex_14.asm ├── Lab 06 ├── Compile and Run C Files with Threads.pdf ├── Ex_06.c ├── Ex_00.c ├── Ex_03.c ├── Ex_02.c ├── Ex_04.c ├── Ex_05.c ├── Ex_01.c └── Compile and Run C Files with Threads.md ├── Lab 05 ├── Ex_35.asm ├── Ex_34.asm ├── Ex_36.asm ├── Ex_39.asm ├── Ex_37.asm ├── Ex_38.asm ├── Lab5 Test.asm └── Ex_40.asm ├── More Examples - Assembly ├── CMP.asm ├── CBW.asm ├── CWD.asm ├── JA.asm └── JG.asm ├── Lab 10 ├── Ex01_ThreadExample.java ├── Ex02_RunnableExample.java ├── Ex08_ExecutorServiceExample.java ├── AccountWithoutSync.java ├── Ex03_VolatileFixExample.java ├── Ex10_FutureExample.java ├── Ex04_SynchronizedExample.java ├── TaskThreadDemo.java ├── Ex09_ExecutorDemo.java ├── Ex06_SemaphoreExample.java ├── Ex05_SimpleLockExample.java ├── Ex07_LockConditionExample.java ├── Ex11_CallableFutureExample.java ├── Lambda Expersion.md └── ArraySum.java ├── Lab 01 ├── Ex_02.asm ├── Ex_01.asm ├── Ex_05.asm ├── Ex_06.asm ├── Ex_04.asm └── Ex_03.asm ├── Lab 02 ├── Ex_08.asm ├── Ex_10.asm ├── Ex_07.asm ├── Ex_09.asm └── Ex_11.asm ├── Lab 04 ├── Ex_32.asm ├── Ex_29.asm ├── Ex_33.asm ├── Ex_28.asm ├── Ex_31.asm └── Ex_30.asm ├── Lab 07 ├── Ex_11.c ├── Ex_13.c ├── Ex_12.c ├── Ex_16.c ├── Ex_07.c ├── Ex_14.c ├── Ex_09.c ├── Ex_08.c ├── Ex_10.c ├── pthread_join.md ├── Ex_15.c ├── struct.c └── struct in C.md ├── Lab 11 ├── Ex19_ThreadLocalExample2.java ├── Ex16_CountdownLatchExample.java ├── Ex17_CyclicBarrierExample.java ├── Ex12_MultiThreadPriorityDemo.java ├── Ex13_WaitNotifyExample.java ├── Ex20_AtomicExample.java ├── Ex15_ReadWriteExample.java ├── Ex14_ProducerConsumer.java └── Ex18_ThreadLocalExample.java ├── Lab 4 - Exercises.md ├── Lab 2 - Exercises.md ├── Lab 5 - Exercises.md ├── Lab 08 ├── ReadersWriters.c ├── Producer-Consumer2.c ├── Producer-Consumer1.c └── dining-philosopher.c ├── Lab 3 - Exercises.md ├── Lab 1 - Exercises.md └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Info/JMP.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Info/JMP.pdf -------------------------------------------------------------------------------- /Info/CMP & Flags.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Info/CMP & Flags.pdf -------------------------------------------------------------------------------- /Info/Comparison.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Info/Comparison.pdf -------------------------------------------------------------------------------- /Lab 1 - Exercises.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Lab 1 - Exercises.pdf -------------------------------------------------------------------------------- /Lab 2 - Exercises.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Lab 2 - Exercises.pdf -------------------------------------------------------------------------------- /Lab 3 - Exercises.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Lab 3 - Exercises.pdf -------------------------------------------------------------------------------- /Lab 4 - Exercises.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Lab 4 - Exercises.pdf -------------------------------------------------------------------------------- /Lab 5 - Exercises.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Lab 5 - Exercises.pdf -------------------------------------------------------------------------------- /Info/Conditional Jump.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Info/Conditional Jump.pdf -------------------------------------------------------------------------------- /Lab 03/Ex_20.asm: -------------------------------------------------------------------------------- 1 | org 100h 2 | 3 | var1 dw 2000h 4 | var2 dw 3000h 5 | 6 | mov ax, var1 7 | xchg ax, var2 8 | mov var1, ax 9 | 10 | ret -------------------------------------------------------------------------------- /Lab 06/Compile and Run C Files with Threads.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mesmatmm/CS306-Spring2025/HEAD/Lab 06/Compile and Run C Files with Threads.pdf -------------------------------------------------------------------------------- /Lab 03/Ex_27.asm: -------------------------------------------------------------------------------- 1 | ORG 100h 2 | DATA DB 5 DUP(10H) 3 | SUM DB ? 4 | 5 | LEA SI, DATA 6 | MOV AL, 0 7 | MOV CX, 5 8 | 9 | L1: 10 | ADD AL, [SI] 11 | INC SI 12 | LOOP L1 13 | 14 | MOV SUM, AL 15 | 16 | RET 17 | -------------------------------------------------------------------------------- /Lab 03/Ex_26.asm: -------------------------------------------------------------------------------- 1 | ORG 100h 2 | 3 | MOV CX, 6 4 | MOV SI, 0 5 | L1: 6 | MOV AL, DATA[SI] 7 | MOV COPY[SI], AL 8 | INC SI 9 | LOOP L1 10 | 11 | RET 12 | 13 | DATA DB 10h, 11h, 12h, 13h, 14h, 15h 14 | COPY DB 6 dup (?) -------------------------------------------------------------------------------- /Lab 03/Ex_21.asm: -------------------------------------------------------------------------------- 1 | org 1010h 2 | 3 | var dw 1020h 4 | copy dw ? 5 | 6 | ; using indirect addressing 7 | 8 | mov si, offset var ; lea si, var 9 | mov di, offset copy ; lea di, copy 10 | 11 | mov ax, [si] 12 | mov [di], ax 13 | 14 | ret -------------------------------------------------------------------------------- /Lab 03/Ex_19.asm: -------------------------------------------------------------------------------- 1 | org 100h 2 | 3 | var dw 1010h, 2020h, 3030h 4 | copy dw 3 dup(?) 5 | 6 | ; Using Direct Offset Addressing 7 | mov ax, var[0] 8 | mov copy[0], ax 9 | 10 | mov ax, var[2] 11 | mov copy[2], ax 12 | 13 | mov ax, var[4] 14 | mov copy[4], ax -------------------------------------------------------------------------------- /Lab 05/Ex_35.asm: -------------------------------------------------------------------------------- 1 | ;The display address of the first character (H) = (41 - 1) x 2 = [80] 2 | 3 | ORG 100h 4 | 5 | MOV AX, 0B800h 6 | MOV DS, AX 7 | 8 | MOV [80], 'H' 9 | MOV [82], 'E' 10 | MOV [84], 'L' 11 | MOV [86], 'L' 12 | MOV [88], 'O' 13 | 14 | RET -------------------------------------------------------------------------------- /Lab 05/Ex_34.asm: -------------------------------------------------------------------------------- 1 | Include 'emu8086.inc' 2 | 3 | ORG 100h 4 | 5 | MOV SI, OFFSET MESSAGE 6 | MOV CX, 5 7 | L1: 8 | PUTC [SI] 9 | INC SI 10 | LOOP L1 11 | 12 | GoTOXY 40, 12 13 | PRINTN 'DISPLAYING IS DONE' ; 18 Characters 14 | RET 15 | 16 | MESSAGE DB 'HELLO' -------------------------------------------------------------------------------- /Lab 05/Ex_36.asm: -------------------------------------------------------------------------------- 1 | ;Solution: 2 | ;The display address of the first character (H) = (0 x 160) + (40 x 2) = [80] 3 | 4 | ORG 100h 5 | 6 | MOV AX, 0B800h 7 | MOV ES, AX 8 | 9 | MOV ES:[80], 'H' 10 | MOV ES:[82], 'E' 11 | MOV ES:[84], 'L' 12 | MOV ES:[86], 'L' 13 | MOV ES:[88], 'O' 14 | 15 | RET -------------------------------------------------------------------------------- /More Examples - Assembly/CMP.asm: -------------------------------------------------------------------------------- 1 | ;Compare. 2 | ; 3 | ;Algorithm: 4 | ; 5 | ;operand1 - operand2 6 | ; 7 | ;result is not stored anywhere, 8 | ;flags are set (OF, SF, ZF, AF, PF, CF) according to result. 9 | ; 10 | ;Example: 11 | 12 | MOV AL, 5 13 | MOV BL, 5 14 | CMP AL, BL ; AL = 5, ZF = 1 (so equal!) 15 | RET -------------------------------------------------------------------------------- /Lab 10/Ex01_ThreadExample.java: -------------------------------------------------------------------------------- 1 | public class Ex01_ThreadExample extends Thread { 2 | @Override 3 | public void run() { 4 | System.out.println("Thread is running: " + Thread.currentThread().getName()); 5 | } 6 | 7 | public static void main(String[] args) { 8 | Ex01_ThreadExample thread = new Ex01_ThreadExample(); 9 | thread.start(); // Starts the new thread 10 | } 11 | } -------------------------------------------------------------------------------- /Lab 03/Ex_24.asm: -------------------------------------------------------------------------------- 1 | ; Ex_24: How many times will the loop executes in the following Assembly program? 2 | 3 | ORG 100h 4 | MOV AX, 0 5 | MOV CX, 0 6 | 7 | L1: 8 | INC AX 9 | LOOP L1 10 | RET 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | ; Solution: 51 | ; 65536 -------------------------------------------------------------------------------- /More Examples - Assembly/CBW.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: .asm 3 | ; Date: 07-March-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | org 100h 7 | 8 | ;Convert byte into word. 9 | ; 10 | ;Algorithm: 11 | ; 12 | ;if high bit of AL = 1 then: 13 | ; AH = 255 (0FFh) 14 | ; 15 | ;else 16 | ; AH = 0 17 | ; 18 | ;Example: 19 | 20 | MOV AX, 0 ; AH = 0, AL = 0 21 | MOV AL, -5 ; AX = 000FBh (251) 22 | CBW ; AX = 0FFFBh (-5) 23 | RET 24 | 25 | ret 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Lab 03/Ex_18.asm: -------------------------------------------------------------------------------- 1 | org 100h 2 | 3 | var db 10h, 11h, 12h, 13h 4 | 5 | ; Using Direct-offset Addressing 6 | mov al, var[0] ; mov al, [var + 0] 7 | mov ah, var[1] ; mov ah, [var + 1] 8 | mov bl, var[2] ; mov bl, [var + 2] 9 | mov bh, var[3] ; mov bh, [var + 3] 10 | 11 | ; Using Index addressing 12 | ; move si, 0 13 | ; mov al, var[si] 14 | ; inc si 15 | ; mov ah, var[si] 16 | ; inc si 17 | ; mov bl, var[si] 18 | ; inc si 19 | ; mov bh, var[si] 20 | 21 | 22 | 23 | ret -------------------------------------------------------------------------------- /More Examples - Assembly/CWD.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: .asm 3 | ; Date: 07-March-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | org 100h 7 | 8 | ;Convert Word to Double word. 9 | ; 10 | ;Algorithm: 11 | ; 12 | ;if high bit of AX = 1 then: 13 | ; DX = 65535 (0FFFFh) 14 | ; 15 | ;else 16 | ; DX = 0 17 | ; 18 | ;Example: 19 | 20 | MOV DX, 0 ; DX = 0 21 | MOV AX, 0 ; AX = 0 22 | MOV AX, -5 ; DX AX = 00000h:0FFFBh 23 | CWD ; DX AX = 0FFFFh:0FFFBh 24 | RET 25 | 26 | ret 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Lab 03/Ex_23.asm: -------------------------------------------------------------------------------- 1 | ; Ex_23: What is the final values of AL and BL registers in the following Assembly program? 2 | 3 | ORG 100h 4 | MOV AL, 4h 5 | MOV BL, 8h 6 | MOV CX, 3 7 | L1: 8 | ADD AL, 2h 9 | INC BL 10 | Loop L1 11 | RET 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | ;Solution: 50 | ;AL = 0Ah 51 | ;BL = 0Bh -------------------------------------------------------------------------------- /Lab 01/Ex_02.asm: -------------------------------------------------------------------------------- 1 | 2 | ; You may customize this and other start-up templates; 3 | ; The location of this template is c:\emu8086\inc\0_com_template.txt 4 | 5 | org 100h 6 | 7 | ; Task a: Initialize AX and DX registers 8 | MOV AX, 1234H ; Load AX with immediate value 1234H 9 | MOV DX, 5678H ; Load DX with immediate value 5678H 10 | 11 | ; Task b: Subtract the word content of AX from the word content of DX 12 | SUB DX, AX ; Subtract AX from DX, result stored in DX 13 | 14 | ret 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Lab 05/Ex_39.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: .asm 3 | ; Date: 10-March-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | include 'emu8086.inc' 7 | 8 | org 100h 9 | 10 | mov cx, 10 11 | mov si, 0 12 | mov al, 0 13 | L1: 14 | cmp al, Grades[si] 15 | JA L2 16 | mov al, Grades[si] 17 | L2: 18 | inc si 19 | Loop L1 20 | mov Max_Grade, al 21 | printn 'Maximum is detected' 22 | ret 23 | 24 | Grades db 69, 87, 96, 45, 13, 55, 100, 73, 37, 66 ; 10 elements 25 | Max_Grade db ? 26 | Message db 'Maximum is detected' 27 | 28 | 29 | -------------------------------------------------------------------------------- /More Examples - Assembly/JA.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: .asm 3 | ; Date: 07-March-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | ;Short Jump if first operand is Above second operand 7 | ; (as set by CMP instruction). Unsigned. 8 | ; 9 | ;Algorithm: 10 | ; 11 | ;if (CF = 0) and (ZF = 0) then jump 12 | ; Example: 13 | 14 | include 'emu8086.inc' 15 | ORG 100h 16 | MOV AL, 250 17 | CMP AL, 5 18 | JA label1 19 | PRINT 'AL is not above 5' 20 | JMP exit 21 | label1: 22 | PRINT 'AL is above 5' 23 | exit: 24 | RET 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Lab 03/Ex_22.asm: -------------------------------------------------------------------------------- 1 | ; Ex_22: Find the final values of AX and BX registers in the following Assembly program? 2 | 3 | Org 100h 4 | MOV AX, 5 5 | MOV BX, 2 6 | JMP S1 7 | Back: INC AX 8 | JMP S2 9 | S1: SUB AX, BX 10 | JMP BACK 11 | S2: DEC BX 12 | ret 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | ;Solution: 51 | ;AX = 0004h 52 | ;BX = 0001h 53 | -------------------------------------------------------------------------------- /Lab 10/Ex02_RunnableExample.java: -------------------------------------------------------------------------------- 1 | public class Ex02_RunnableExample implements Runnable { 2 | @Override 3 | public void run() { 4 | System.out.println("Runnable is running: " + Thread.currentThread().getName()); 5 | } 6 | 7 | public static void main(String[] args) { 8 | Ex02_RunnableExample runnable = new Ex02_RunnableExample(); 9 | Thread thread1 = new Thread(runnable); 10 | Thread thread2 = new Thread(runnable); 11 | thread1.start(); 12 | thread2.start(); 13 | } 14 | } -------------------------------------------------------------------------------- /More Examples - Assembly/JG.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: .asm 3 | ; Date: 07-March-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | ; Short Jump if first operand is Greater then 7 | ; second operand (as set by CMP instruction). Signed. 8 | 9 | ;Algorithm: 10 | ; 11 | ;if (ZF = 0) and (SF = OF) then jump 12 | ;Example: 13 | include 'emu8086.inc' 14 | ORG 100h 15 | MOV AL, 5 16 | CMP AL, -5 17 | JG label1 18 | PRINT 'AL is not greater -5.' 19 | JMP exit 20 | label1: 21 | PRINT 'AL is greater -5.' 22 | exit: 23 | RET 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Lab 01/Ex_01.asm: -------------------------------------------------------------------------------- 1 | 2 | 3 | org 100h 4 | 5 | ; Task a: Initialize AX and SI registers 6 | MOV AX, 1520H ; Load AX with immediate value 1520H 7 | MOV SI, 0300H ; Load SI with immediate value 0300H 8 | 9 | ; Task b: Save the immediate value 3040H at the memory location addressed by SI 10 | MOV [SI], 3040H ; Store 3040H at the memory location pointed to by SI 11 | 12 | ; Task c: Add the word contents at the memory location addressed by SI to AX 13 | ADD AX, [SI] ; Add the value at memory location [SI] to AX 14 | 15 | ret 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Lab 01/Ex_05.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Set the origin to 100h (typical for COM programs in DOS) 2 | 3 | ; Task a: Initialize AL and SI registers 4 | MOV AL, 33H ; Load AL with immediate value 33H 5 | MOV SI, 0300H ; Load SI with immediate value 0300H 6 | 7 | ; Task b: Copy 55H to the data segment memory location addressed by SI 8 | MOV [SI], 55H ; Store 55H at the memory location pointed to by SI 9 | 10 | ; Swap between AL and the data at the data segment memory location addressed by SI 11 | XCHG AL, [SI] ; Swap AL with the value at memory location [SI] 12 | 13 | 14 | ret ; Return to the operating system (end of the program) -------------------------------------------------------------------------------- /Lab 02/Ex_08.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Set the origin to 100h (typical for COM programs in DOS) 2 | 3 | ; A) Initialize AX and BX registers 4 | MOV AX, 100H 5 | MOV BX, 200H 6 | 7 | ; B) Operations on AX and BX 8 | ADD AX, 50H ; Add 50h to AX 9 | INC AX ; Increase AX by one 10 | SUB BX, 50H ; Subtract 50h from BX 11 | DEC BX ; Decrease BX by one 12 | XCHG AX, BX ; Swap AX and BX 13 | 14 | ; C) Save data into memory and perform addition 15 | MOV [600H], 300H ; Save 300h at address 600h 16 | MOV [602H], 400H ; Save 400h at address 602h (consecutive address) 17 | MOV CX, [600H] ; Load 300h into CX 18 | ADD CX, [602H] ; Add 400h to CX (result in CX) 19 | 20 | ret ; Return to the operating system (end of the program) -------------------------------------------------------------------------------- /Lab 03/Ex_12.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: Ex_12.asm 3 | ; Date: Day-Month-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | org 100h ; Set the origin (starting address) of the program to 100h (typical for .COM files) 7 | 8 | sum dw ? ; Define a variable 'sum' of type word (16-bit), uninitialized 9 | 10 | mov al, 6 ; Load the value 6 into the AL register (AL = 6) 11 | mov bl, 7 ; Load the value 7 into the BL register (BL = 7) 12 | 13 | mul bl ; Multiply AL by BL (6 * 7 = 42), result stored in AX (16-bit result) 14 | 15 | mov cl, 2 ; Load the value 2 into the CL register (CL = 2) 16 | div cl ; Divide AX by CL (42 / 2 = 21), result stored in AL (quotient) 17 | 18 | mov sum, ax ; Move the result in AX (21) into the 'sum' variable 19 | 20 | ret ; Return from the program (end execution) 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Lab 01/Ex_06.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Set the origin to 100h (typical for COM programs in DOS) 2 | 3 | ; Task a: Initialize AL and DL registers 4 | MOV AL, 38H ; Load AL with immediate value 38H 5 | MOV DL, 0E0H ; Load DL with immediate value 0E0H 6 | 7 | ; Task b: Set the rightmost 5-bits of DL without changing the remaining bits 8 | OR DL, 00011111B ; Set the rightmost 5 bits of DL (1FH = 00011111B) 9 | 10 | ; Task c: Set the leftmost 3-bits of AL, clear bits 2, 3, and 4 of AL, and invert the rightmost 2 bits of AL 11 | OR AL, 11100000B ; Set the leftmost 3 bits of AL (E0H = 11100000B) 12 | AND AL, 11100011B ; Clear bits 2, 3, and 4 of AL (E3H = 11100011B) 13 | XOR AL, 00000011B ; Invert the rightmost 2 bits of AL (03H = 00000011B) 14 | 15 | 16 | ret ; Return to the operating system (end of the program) 17 | -------------------------------------------------------------------------------- /Lab 03/Ex_25.asm: -------------------------------------------------------------------------------- 1 | ; Ex_25: What is the final values of AL and BL registers in the following program? 2 | 3 | ORG 100h 4 | MOV AX, 0 5 | MOV BX, 0 6 | MOV CX, COUNT ;set outer loop count 7 | L1: 8 | INC BL ;BL = BL + 1 9 | MOV COUNT, CX ;save outer loop count 10 | MOV CX, 2 ;set inner loop count 11 | L2: 12 | INC AL ;AL = AL + 1 13 | LOOP L2 ;repeat the inner loop 14 | MOV CX, COUNT ;restore outer loop count 15 | LOOP L1 ;repeat the outer loop 16 | RET 17 | COUNT DW 5 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | ; Solution: 62 | ; AL = 0Ah 63 | ; BL = 05h -------------------------------------------------------------------------------- /Lab 02/Ex_10.asm: -------------------------------------------------------------------------------- 1 | 2 | 3 | ; File Name: .asm 4 | ; Date: 11-Feb-2025 5 | ; Author: Mahmoud Esmat 6 | 7 | org 100h 8 | 9 | area DW ? ; Variable to store the area of the rectangle 10 | half_area DW ? ; Variable to store half of the area 11 | %DW = Define WORD 12 | 13 | ; Initialize dimensions 14 | MOV AL, 7H ; Load 7h into AL 15 | MOV BL, 3H ; Load 3h into BL 16 | 17 | ; Calculate the area (7h * 3h) 18 | MUL BL ; AX = AL * BL (7h * 3h = 15h) 19 | MOV area, AX ; Save the area into the 'area' variable 20 | 21 | ; Calculate half of the area (15h / 2) 22 | MOV BL, 2 23 | DIV BL ; Divide AX by 2 (15h / 2 = 0Ah with remainder 1) 24 | ; result will be in AX 25 | MOV half_area, AX ; Save half of the area into the 'half_area' variable 26 | 27 | ; End of program 28 | MOV AH, 4CH 29 | INT 21H 30 | 31 | ret 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Lab 04/Ex_32.asm: -------------------------------------------------------------------------------- 1 | ORG 100h ; Set the program's origin address at 100h 2 | 3 | MOV AL, VAR1 ; Load the first variable (VAR1) into register AL 4 | MOV BL, VAR2 ; Load the second variable (VAR2) into register BL 5 | 6 | CMP AL, BL ; Compare AL with BL 7 | JA LARGER ; If AL > BL (unsigned comparison), jump to LARGER label 8 | 9 | MOV LOW, AL ; If AL <= BL, store AL (smaller value) in LOW 10 | MOV HIGH, BL ; Store BL (larger value) in HIGH 11 | JMP STOP ; Jump to STOP to exit the program 12 | 13 | LARGER: 14 | MOV HIGH, AL ; If AL > BL, store AL (larger value) in HIGH 15 | MOV LOW, BL ; Store BL (smaller value) in LOW 16 | 17 | STOP: 18 | RET ; Return from the program 19 | 20 | VAR1 DB 7Fh ; Define VAR1 with the value 7Fh (127 in decimal) 21 | VAR2 DB 80h ; Define VAR2 with the value 80h (128 in decimal) 22 | LOW DB ? 23 | HIGH DB ? -------------------------------------------------------------------------------- /Lab 02/Ex_07.asm: -------------------------------------------------------------------------------- 1 | 2 | 3 | org 100h ; Set the origin to 100h (typical for COM programs in DOS) 4 | 5 | ; Task a: Initialize AX, BX, and DI registers 6 | MOV AX, 1020H ; Load AX with immediate value 1020H 7 | MOV BX, 3040H ; Load BX with immediate value 3040H 8 | MOV DI, 0200H ; Load DI with immediate value 0200H 9 | 10 | ; Task b: One's complement the low byte of AX register 11 | NOT AL ; One's complement of AL (low byte of AX) 12 | 13 | ; Task c: Two's complement the high byte of BX register 14 | NEG BH ; Two's complement of BH (high byte of BX) 15 | 16 | ; Task d: Save the high byte of AX and the low byte of BX at memory locations addressed by DI 17 | MOV [DI], AH ; Save AH (high byte of AX) at memory location [DI] 18 | MOV [DI+1], BL ; Save BL (low byte of BX) at memory location [DI+1] 19 | 20 | ret ; Return to the operating system (end of the program) 21 | -------------------------------------------------------------------------------- /Lab 02/Ex_09.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Set the origin to 100h (typical for COM programs in DOS) 2 | 3 | ; A) Initialize AX register by FF00h 4 | MOV AX, 0FF00H 5 | 6 | ; Set the rightmost 8 bits of AX 7 | OR AX, 0000000011111111B 8 | ;OR AX, 00FFH 9 | 10 | ; Clear bits 8 and 9 of AX 11 | AND AX, 0000111111001111B 12 | ;AND AX, 0FCFFH 13 | 14 | ; Invert the leftmost 6 bits of AX and store the result in BX 15 | MOV BX, AX 16 | XOR BX, 1111110000000000B 17 | ;XOR BX, 0FC00H ; Invert the leftmost 6 bits 18 | 19 | ; B) Initialize the low order byte of CX by EFh and save its one's complement at the high order byte 20 | MOV CL, 0EFH 21 | MOV CH, CL 22 | NOT CH ; One's complement of EFh 23 | 24 | ; C) Initialize the low order byte of DX by EFh and save its 2's complement at the high order byte 25 | MOV DL, 0EFH 26 | MOV DH, DL 27 | NEG DH ; Two's complement of EFh 28 | 29 | ret ; Return to the operating system (end of the program) 30 | -------------------------------------------------------------------------------- /Lab 04/Ex_29.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Set origin for a DOS .COM program (starts at offset 100h) 2 | 3 | mov cx, 41 ; Set loop counter to 41 (length of the string) 4 | mov si, 0 ; Initialize index SI to 0 5 | 6 | CopyData: 7 | mov al, source[si] ; Load the character from SOURCE at index SI into AL 8 | mov target[si], al ; Store the character from AL into TARGET at the same index 9 | inc si ; Increment SI to move to the next character 10 | loop CopyData ; Decrement CX and repeat if CX != 0 11 | 12 | ret ; Return control to the operating system 13 | 14 | SOURCE db 'Assembly language is a low level language' ; Define the source string 15 | TARGET db 41 dup(?) ; Reserve 41 bytes for TARGET (uninitialized) 16 | 17 | 18 | 19 | ;lea si, source 20 | ;lea di, target 21 | ;mov cx, 41 22 | ;Exchange: 23 | ; mov al, [si] 24 | ; mov [di], al 25 | ; inc si 26 | ; inc di 27 | ;loop exchange 28 | -------------------------------------------------------------------------------- /Lab 04/Ex_33.asm: -------------------------------------------------------------------------------- 1 | ORG 100h ; Set the program's origin address at 100h 2 | 3 | MOV AL, VAR1 ; Load the first signed variable (VAR1) into register AL 4 | MOV BL, VAR2 ; Load the second signed variable (VAR2) into register BL 5 | 6 | CMP AL, BL ; Compare AL with BL (signed comparison) 7 | JG LARGER ; If AL > BL (signed comparison), jump to LARGER label 8 | 9 | ; If AL is not greater than BL (i.e., AL <= BL) 10 | MOV LOW, AL ; Store AL (smaller value) in LOW 11 | MOV HIGH, BL ; Store BL (larger value) in HIGH 12 | JMP STOP ; Jump to STOP to exit the program 13 | 14 | LARGER: 15 | MOV HIGH, AL ; If AL > BL, store AL (larger value) in HIGH 16 | MOV LOW, BL ; Store BL (smaller value) in LOW 17 | 18 | STOP: 19 | RET ; Return from the program 20 | 21 | VAR1 DB 7Fh ; Define VAR1 with the value 7Fh (+127 in signed decimal) 22 | VAR2 DB 80h ; Define VAR2 with the value 80h (-128 in signed decimal) 23 | LOW DB ? 24 | HIGH DB ? -------------------------------------------------------------------------------- /Lab 10/Ex08_ExecutorServiceExample.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.concurrent.*; 3 | 4 | public class Ex08_ExecutorServiceExample { 5 | public static void main(String[] args) { 6 | // Create a thread pool with 2 threads 7 | ExecutorService executor = Executors.newFixedThreadPool(2); 8 | //ExecutorService executor = Executors.newCachedThreadPool(); 9 | 10 | // Submit tasks to the executor 11 | executor.submit(() -> { 12 | System.out.println("Task 1 running in " + Thread.currentThread().getName()); 13 | }); 14 | 15 | executor.submit(() -> { 16 | System.out.println("Task 2 running in " + Thread.currentThread().getName()); 17 | }); 18 | 19 | executor.submit(() -> { 20 | System.out.println("Task 3 running in " + Thread.currentThread().getName()); 21 | }); 22 | // Shutdown the executor 23 | executor.shutdown(); 24 | System.out.println("MAIN ENDED"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Lab 01/Ex_04.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Set the origin to 100h (typical for COM programs in DOS) 2 | 3 | ; Task a: Copy the string data 'NO' into AX register 4 | MOV AX, 'NO' ; Load AX with the string 'NO' (4F4E in hexadecimal) 5 | 6 | ; Initialize SI and BP registers 7 | MOV SI, 0200H ; Load SI with 0200H 8 | MOV BP, 0100H ; Load BP with 0100H 9 | 10 | ; Copy AX into stack segment memory location addressed by SI+BP+20H 11 | MOV SS:[SI+BP+20H], AX ; Copy AX to stack segment memory location SI+BP+20H 12 | 13 | ; Task b: Initialize DI with 0300H 14 | MOV DI, 0300H ; Load DI with 0300H 15 | 16 | ; Copy the string 'HELLO' into extra data segment memory locations addressed by DI+100H 17 | MOV ES:[DI+100H], 'HE' ; Copy 'HE' to memory location DI+100H in extra segment 18 | MOV ES:[DI+102H], 'LL' ; Copy 'LL' to memory location DI+102H in extra segment 19 | MOV ES:[DI+104H], 'O' ; Copy 'O' to memory location DI+104H in extra segment 20 | 21 | ret ; Return to the operating system (end of the program) -------------------------------------------------------------------------------- /Lab 05/Ex_37.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Set the origin (starting address) of the program to 100h (typical for .COM files) 2 | 3 | mov al, var[0] ; Load the first byte (80h) from the variable 'var' into the AL register 4 | cbw ; Convert the byte in AL to a word in AX (sign-extend AL to AX) 5 | mov dx, ax ; Move the value in AX (sign-extended 80h) to DX 6 | 7 | mov al, var[1] ; Load the second byte (0FFh) from the variable 'var' into the AL register 8 | cbw ; Convert the byte in AL to a word in AX (sign-extend AL to AX) 9 | add ax, dx ; Add the value in DX (sign-extended 80h) to AX (sign-extended 0FFh) 10 | mov sum, ax ; Store the result (sum) in the variable 'sum' 11 | 12 | printn 'All done' ; Print the message 'All done' to the screen (assuming this is a macro or function) 13 | 14 | ret ; Return from the program (end execution) 15 | 16 | var db 80h, 0ffh ; Define a byte array 'var' with two values: 80h and 0FFh 17 | sum dw ? ; Define a word-sized variable 'sum' to store the result (uninitialized) -------------------------------------------------------------------------------- /Lab 03/Ex_16.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Start the program at memory location 100h (typical for .COM files) 2 | 3 | ; Define data 4 | var1 db 15h ; Define a byte variable `var1` with value 15h (21 in decimal) 5 | var2 db 20h ; Define a byte variable `var2` with value 20h (32 in decimal) 6 | var3 db 10h ; Define a byte variable `var3` with value 10h (16 in decimal) 7 | result dw ? ; Reserve a word (2 bytes) for storing the result 8 | 9 | ; Perform calculations 10 | neg var1 ; Negate the value of `var1` (two's complement). 15h becomes -15h (or -21 in decimal) 11 | mov al, var1 ; Move the negated value of `var1` into the AL register (8-bit) 12 | add al, var2 ; Add the value of `var2` (20h) to AL. AL now contains (-15h + 20h) = 0Bh (11 in decimal) 13 | mul var3 ; Multiply AL by `var3` (10h). The result is stored in AX (16-bit), since `mul` uses AL * operand. 14 | 15 | ; Store the result 16 | mov result, ax ; Move the result of the multiplication (stored in AX) into the `result` variable 17 | 18 | ret ; Return from the program (end execution) -------------------------------------------------------------------------------- /Lab 03/Ex_13.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: Ex_13.asm 3 | ; Date: Day-Month-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | org 100h ; Set the origin (starting address) of the program to 100h (typical for .COM files) 7 | 8 | sale dw ? ; Define a variable 'sale' of type word (16-bit), uninitialized 9 | s_price dw ? ; Define a variable 's_price' of type word (16-bit), uninitialized 10 | 11 | mov ax, 6000 ; Load the original price (6000 LE) into the AX register 12 | mov bx, 20 ; Load the sale rate (20%) into the BX register 13 | mul bx ; Multiply AX (6000) by BX (20), result in AX = 120000 (6000 * 20) 14 | 15 | mov cx, 100 ; Load the value 100 into the CX register 16 | div cx ; Divide AX (120000) by CX (100), result in AX = 1200 (120000 / 100) 17 | mov sale, ax ; Store the sale amount (1200) in the 'sale' variable 18 | 19 | mov cx, 6000 ; Load the original price (6000) into the CX register 20 | sub cx, sale ; Subtract the sale amount (1200) from the original price (6000), result in CX = 4800 21 | mov s_price, cx ; Store the final sale price (4800) in the 's_price' variable 22 | 23 | ret ; Return from the program (end execution) 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Lab 04/Ex_28.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Set origin for a DOS .COM program (starts at offset 100h) 2 | 3 | lea si, data ; Load effective address of 'data' array into SI register 4 | mov cx, 16 ; Set loop counter to 16 (processing 16 elements) 5 | mov bl, 00h ; Initialize bl to 0 (starting value for array elements) 6 | mov al, 00h ; Initialize al to 0 (used to store sum) 7 | 8 | ArrayData: 9 | mov [si], bl ; Store the value of bl into the array at SI 10 | add al, [si] ; Add the value at SI to al (accumulate sum) 11 | inc si ; Move to the next array element 12 | loop ArrayData ; Decrement CX and repeat if CX != 0 13 | 14 | mov sum, al ; Store total sum into 'sum' variable 15 | mov dl, 16 ; Load divisor (16) into dl for average calculation 16 | div dl ; Divide AX by 16, quotient in AL (remainder in AH) 17 | mov avg, ax ; Store the calculated average in 'avg' 18 | 19 | ret ; Return control to the operating system 20 | 21 | data db 16 dup(?) ; Declare an array of 16 bytes (uninitialized) 22 | sum db ? ; Reserve a byte for storing sum 23 | avg dw ? ; Reserve a word (2 bytes) for storing average 24 | -------------------------------------------------------------------------------- /Lab 05/Ex_38.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: .asm 3 | ; Date: 10-March-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | ;include 'emu8086.inc' 7 | 8 | org 100h 9 | 10 | mov cx, 7 11 | mov si, 0 12 | mov al, 0 13 | mov ah, 0 14 | L1: 15 | add al, data[si] 16 | inc si 17 | jnc L2 18 | adc ah, 0 19 | L2: 20 | Loop L1 21 | mov sum, ax 22 | mov bl, 8 23 | div bl 24 | mov AVGQ, al 25 | mov AVGR, ah 26 | 27 | 28 | mov ax, 0B800h ; Correct segment for display memory 29 | mov es, ax ; Set ES to point to the display memory segment 30 | 31 | ;The display address of the first character (H) = (81 - 1) x 2 = [160] 32 | 33 | mov si, 0 34 | mov di, 160 35 | mov CX, 17 36 | 37 | L3: 38 | mov al, DISM[si] ; Load the character from the string into AL 39 | mov es:[di], al ; Write the character to the display memory 40 | add di, 2 ; Move to the next character position (skip attribute byte) 41 | inc si ; Move to the next character in the string 42 | LOOP L3 43 | 44 | 45 | 46 | ret 47 | data db 7fh, 0b2h, 35h, 0feh, 0c9h, 80h, 9eh, 11h 48 | sum dw ? 49 | avgq db ? 50 | avgr db ? 51 | DISM db 'summation is done' ;17 characters 52 | 53 | -------------------------------------------------------------------------------- /Lab 06/Ex_06.c: -------------------------------------------------------------------------------- 1 | /* 2 | create one thread 3 | passing paramter to the load function 4 | using sleep function 5 | */ 6 | 7 | #include // Include the pthread library 8 | #include // Standard I/O library 9 | #include // For sleep function 10 | 11 | // Function to be executed by the thread 12 | void *print_numbers(void *arg) 13 | { 14 | int *n = (int *)arg; // Cast the argument to an integer pointer 15 | for (int i = 1; i <= *n; i++) 16 | { 17 | printf("Thread: %d\n", i); 18 | //sleep(1); // Sleep for 1 second to simulate work 19 | } 20 | return NULL; // Return null when done 21 | } 22 | 23 | int main() 24 | { 25 | pthread_t thread_id; // Declare a thread identifier 26 | int num = 5; // Number of iterations for the thread to print 27 | 28 | // Create the thread 29 | if (pthread_create(&thread_id, NULL, print_numbers, &num) != 0) 30 | { 31 | perror("Failed to create thread"); 32 | return 1; 33 | } 34 | 35 | // Wait for the thread to complete 36 | if (pthread_join(thread_id, NULL) != 0) 37 | { 38 | perror("Failed to join thread"); 39 | return 1; 40 | } 41 | 42 | printf("Main thread: All tasks are complete.\n"); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Lab 03/Ex_15.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Start the program at memory location 100h (typical for .COM files) 2 | 3 | ; Define data 4 | marks db 60, 80, 90 ; Define an array of marks with values 60, 80, and 90 5 | sum dw ? ; Reserve a word (2 bytes) for storing the sum of marks 6 | avg dw ? ; Reserve a word (2 bytes) for storing the average of marks 7 | 8 | ; Calculate the sum of marks 9 | mov al, marks[0] ; Load the first mark (60) into AL (8-bit register) 10 | add al, marks[1] ; Add the second mark (80) to AL 11 | add al, marks[2] ; Add the third mark (90) to AL 12 | mov sum, ax ; Store the result (sum) in the 'sum' variable (AX is 16-bit, so it includes AL)) 13 | 14 | ; Calculate the average of marks 15 | mov bl, 3 ; Load the divisor (number of marks, which is 3) into BL 16 | div bl ; Divide AX (sum) by BL (3). The quotient (average) is stored in AL 17 | mov avg, ax ; Store the result (average) in the 'avg' variable 18 | 19 | ; Load effective addresses of variables 20 | lea si, sum ; Load the address of 'sum' into SI (equivalent to 'mov si, offset sum') 21 | lea di, avg ; Load the address of 'avg' into DI (equivalent to 'mov di, offset avg') 22 | 23 | ret ; Return from the program (end execution) -------------------------------------------------------------------------------- /Lab 06/Ex_00.c: -------------------------------------------------------------------------------- 1 | #include // Include the standard input/output library 2 | 3 | int fun1(int x, int y); // function prototype 4 | void references_and_pointers(); 5 | void test(); 6 | 7 | // The main function - entry point of the program 8 | int main() 9 | { 10 | //test(); 11 | references_and_pointers(); 12 | 13 | // Return 0 to indicate successful execution 14 | return 0; 15 | } 16 | void test() 17 | { 18 | // Print a message to the console 19 | printf("Welcome to C!\n"); 20 | int x = 7; 21 | int y = 5; 22 | printf("x + y = %d \n", fun1(x, y)); 23 | 24 | } 25 | 26 | int fun1(int x, int y) 27 | { 28 | return x + y; 29 | } 30 | 31 | void references_and_pointers() { 32 | int x = 10; // Variable 33 | int *ptr = &x; // Pointer to 'x' 34 | //int &ref = x; // Reference to 'x' //In C, there is no direct concept of a "reference" as in C++ 35 | 36 | printf("Value of x: %d\n", x); // Output: Value of x: 10 37 | printf("Address of x: %p\n", &x); // Output: Address of x: (memory address) 38 | printf("Value of ptr: %p\n", ptr); // Output: Value of ptr: (same memory address as &x) 39 | printf("Value pointed by ptr: %d\n", *ptr); // Output: Value pointed by ptr: 10 40 | 41 | //printf("Value of x: %d\n", ref); 42 | 43 | } -------------------------------------------------------------------------------- /Lab 02/Ex_11.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: .asm 3 | ; Date: 11-Feb-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | org 100h 7 | 8 | factorial5 DW ? ; Variable to store the factorial of 5 9 | 10 | ; Initialize AX with 1 (to store the result) 11 | MOV AX, 1 12 | 13 | ; Calculate 5! = 5 * 4 * 3 * 2 * 1 14 | MOV CX, 5 ; Load 5 into CX 15 | MUL CX ; AX = AX * 5 (1 * 5 = 5) 16 | 17 | MOV CX, 4 ; Load 4 into CX 18 | MUL CX ; AX = AX * 4 (5 * 4 = 20) 19 | 20 | MOV CX, 3 ; Load 3 into CX 21 | MUL CX ; AX = AX * 3 (20 * 3 = 60) 22 | 23 | MOV CX, 2 ; Load 2 into CX 24 | MUL CX ; AX = AX * 2 (60 * 2 = 120) 25 | 26 | MOV CX, 1 ; Load 1 into CX 27 | MUL CX ; AX = AX * 1 (120 * 1 = 120) 28 | 29 | ; Save the result into factorial5 variable 30 | MOV factorial5, AX 31 | 32 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 33 | 34 | ;; Initialize the number for which factorial is to be calculated 35 | ;MOV CX, 5 ; Load 5 into CX (counter) 36 | ;MOV AX, 1 ; Initialize AX with 1 (to store the result) 37 | ; 38 | ;; Calculate factorial 39 | ;FACTORIAL_LOOP: 40 | ; MUL CX ; AX = AX * CX 41 | ; LOOP FACTORIAL_LOOP ; Decrement CX and loop until CX is 0 42 | ; 43 | ;; Save the result into factorial5 variable 44 | ;MOV factorial5, AX 45 | 46 | ret 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Lab 01/Ex_03.asm: -------------------------------------------------------------------------------- 1 | 2 | ;Ex_03.asm 3 | 4 | org 100h 5 | 6 | ; Task a: Initialize AL, BL, CL, and DL registers 7 | MOV AL, 10H ; Load AL with immediate value 10H 8 | MOV BL, 20H ; Load BL with immediate value 20H 9 | MOV CL, 30H ; Load CL with immediate value 30H 10 | MOV DL, 40H ; Load DL with immediate value 40H 11 | 12 | ; Task b: Copy contents of AL, BL, CL, DL into BH, CH, DH, AL 13 | MOV BH, AL ; Copy AL to BH 14 | MOV CH, BL ; Copy BL to CH 15 | MOV DH, CL ; Copy CL to DH 16 | MOV AH, DL ; Copy DL to AH (DL is part of DX) 17 | 18 | ; Task c: SWAP between AX and BX registers 19 | XCHG AX, BX ; Swap AX and BX 20 | 21 | ; Task d: Copy AX to memory location 0200h, then BX and CX to consecutive addresses 22 | MOV [0200H], AX ; Copy AX to memory location 0200H 23 | MOV [0202H], BX ; Copy BX to memory location 0202H 24 | MOV [0204H], CX ; Copy CX to memory location 0204H 25 | 26 | ; Task e: Copy DX to stack segment memory location 0100h, then 4433h and 2211h to consecutive addresses 27 | MOV SS:[0100H], DX ; Copy DX to stack segment memory location 0100H 28 | MOV SS:[0102H], 4433H ; Copy 4433H to stack segment memory location 0102H 29 | MOV SS:[0104H], 2211H ; Copy 2211H to stack segment memory location 0104H 30 | 31 | ret ; Return to the operating system (end of the program) 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Lab 10/AccountWithoutSync.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.*; 2 | 3 | public class AccountWithoutSync { 4 | private static Account account = new Account(); 5 | 6 | public static void main(String[] args) { 7 | ExecutorService executor = Executors.newCachedThreadPool(); 8 | 9 | // Create and launch 100 threads 10 | for (int i = 0; i < 100; i++) { 11 | executor.execute(new AddAPennyTask()); 12 | } 13 | 14 | executor.shutdown(); 15 | 16 | // Wait until all tasks are finished 17 | while (!executor.isTerminated()) { 18 | } 19 | 20 | System.out.println("What is balance? " + account.getBalance()); 21 | } 22 | 23 | // A thread for adding a penny to the account 24 | private static class AddAPennyTask implements Runnable { 25 | public void run() { 26 | account.deposit(1); 27 | } 28 | } 29 | 30 | // An inner class for account 31 | private static class Account { 32 | private int balance = 0; 33 | 34 | public int getBalance() { 35 | return balance; 36 | } 37 | 38 | public void deposit(int amount) { 39 | int newBalance = balance + amount; 40 | 41 | // This delay is deliberately added to magnify the 42 | // data-corruption problem and make it easy to see. 43 | // try { 44 | // Thread.sleep(5); 45 | // } 46 | // catch (InterruptedException ex) { 47 | // } 48 | 49 | balance = newBalance; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Lab 03/Ex_17.asm: -------------------------------------------------------------------------------- 1 | org 100h ; Start the program at memory address 100h (typical for .COM files in DOS) 2 | 3 | marks db 10, 20, 30 ; Define an array of marks with 3 values 4 | copy db 2 dup(?) ; Reserve space for 2 bytes to store a copy of the first two marks 5 | 6 | ; Using Indirect Addressing to copy values from 'marks' to 'copy' 7 | 8 | lea si, marks ; Load the address of 'marks' into the SI register (Source Index) 9 | lea di, copy ; Load the address of 'copy' into the DI register (Destination Index) 10 | 11 | 12 | mov al, [si] ; Copy the first value from 'marks' (pointed to by SI) to AL register 13 | mov [di], al ; Store the value in AL into the first position of 'copy' (pointed to by DI) 14 | 15 | 16 | inc si ; Increment SI to point to the next value in 'marks' 17 | inc di ; Increment DI to point to the next position in 'copy' 18 | 19 | mov al, [si] ; Copy the second value from 'marks' (pointed to by SI) to AL register 20 | mov [di], al ; Store the value in AL into the second position of 'copy' (pointed to by DI) 21 | 22 | 23 | ret ; End of the program 24 | 25 | ; Using Direct offset Addressing 26 | ; mov al, marks[0] ; move al, [marks] 27 | ; mov copy[0], al ; mov [copy], al 28 | 29 | ; mov al, marks[1] ; move al, [marks+1] 30 | ; mov copy[1], al ; mov [copy+1], al 31 | 32 | ; Using Index Addressing 33 | ; mov si, 0 34 | ; mov al, marks[si] 35 | ; mov copy[si], ai 36 | ; inc si 37 | ; mov al, marks[si] 38 | ; mov copy[si], ai -------------------------------------------------------------------------------- /Lab 04/Ex_31.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: Ex_31.asm 3 | ; Date: 03-March-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | org 100h ; Set the origin at memory address 100h 7 | 8 | mov ax, 800h ; Load segment address 0800h into AX 9 | mov ds, ax ; Set DS (Data Segment) to 0800h 10 | 11 | mov si, 200h ; Set SI to start of first block (0800h:0200h) 12 | mov cx, 1024 ; Set loop counter for 1 Kbyte (1024 bytes) 13 | mov di, 600h ; Set DI to start of second block (0800h:0600h) 14 | 15 | ; Fill block1 with 7Eh and block2 with E7h 16 | Blocks: 17 | mov [si], 7eh ; Store 7Eh in block1 at address SI 18 | mov [di], 0e7h ; Store E7h in block2 at address DI 19 | inc si ; Move to the next byte in block1 20 | inc di ; Move to the next byte in block2 21 | loop Blocks ; Repeat for 1024 bytes 22 | 23 | ; Reset SI and DI to the start of the blocks for exchange 24 | mov si, 200h ; Reset SI to start of block1 25 | mov di, 600h ; Reset DI to start of block2 26 | mov cx, 1024 ; Reset loop counter for exchange process 27 | 28 | ; Exchange block1 and block2 contents 29 | Exchange: 30 | mov al, [si] ; Load value from block1 into AL 31 | xchg al, [di] ; Swap AL with value in block2 32 | mov [si], al ; Store exchanged value in block1 33 | inc si ; Move to next byte in block1 34 | inc di ; Move to next byte in block2 35 | loop Exchange ; Repeat for 1024 bytes 36 | 37 | ret ; Return to operating system 38 | -------------------------------------------------------------------------------- /Lab 10/Ex03_VolatileFixExample.java: -------------------------------------------------------------------------------- 1 | public class Ex03_VolatileFixExample { 2 | private static volatile boolean flag = false; // Now volatile! 3 | 4 | public static void main(String[] args) { 5 | // Thread 1: Checks the flag 6 | new Thread(() -> { 7 | while (!flag) { 8 | // Waits until flag becomes true 9 | } 10 | System.out.println("Thread 1: Flag is now TRUE!"); 11 | }).start(); 12 | 13 | // Thread 2: Changes the flag after 1 second 14 | new Thread(() -> { 15 | try { 16 | Thread.sleep(1000); 17 | flag = true; 18 | System.out.println("Thread 2: Flag set to TRUE"); 19 | } catch (InterruptedException e) { 20 | e.printStackTrace(); 21 | } 22 | }).start(); 23 | } 24 | } 25 | /* 26 | Problem Without volatile: 27 | - Thread 1 might never see the updated value of flag from Thread 2 due to CPU caching. 28 | 29 | Key Points: 30 | ✔ volatile ensures Thread 1 immediately sees changes made by Thread 2. 31 | ✔ Without volatile, Java might cache the value of flag in Thread 1's CPU cache. 32 | ✔ Use volatile when one thread writes, and another thread reads a variable. 33 | 34 | When to Use volatile? 35 | - For simple flags (like boolean flag). 36 | - When only one thread updates the variable. 37 | - For lightweight synchronization (but for complex operations, use synchronized or Lock instead). 38 | 39 | */ -------------------------------------------------------------------------------- /Lab 07/Ex_11.c: -------------------------------------------------------------------------------- 1 | // Multiple threads accessing shared memory location 2 | // Without any syrchronization 3 | /* 4 | A race condition occurs when two threads try to modify a shared variable 5 | without synchronization, leading to unpredictable results. 6 | However, race conditions are not guaranteed to happen every 7 | time—they depend on how threads are scheduled by the OS. 8 | */ 9 | #include 10 | #include 11 | #include // For exit() 12 | 13 | int shared_data = 0; // Shared resource 14 | 15 | void *increment(void *arg) 16 | { 17 | for (int i = 0; i < 100000; i++) 18 | { 19 | shared_data++; // Access the shared resource 20 | // shared_data = shared_data + 1; 21 | } 22 | return NULL; 23 | } 24 | 25 | int main() 26 | { 27 | int num_threads = 5; 28 | pthread_t threads[5]; // Array to store thread IDs 29 | 30 | // Create threads 31 | for (int i = 0; i < num_threads; i++) 32 | { 33 | if (pthread_create(&threads[i], NULL, increment, NULL) != 0) 34 | { 35 | perror("Failed to create thread"); 36 | exit(EXIT_FAILURE); 37 | } 38 | } 39 | 40 | // Wait for all threads to finish 41 | for (int i = 0; i < num_threads; i++) 42 | { 43 | if (pthread_join(threads[i], NULL) != 0) 44 | { 45 | perror("Failed to join thread"); 46 | exit(EXIT_FAILURE); 47 | } 48 | } 49 | 50 | printf("Final value of shared_data: %d\n", shared_data); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /Lab 07/Ex_13.c: -------------------------------------------------------------------------------- 1 | // Thread-Safe Stack (Intermediate) 2 | // Problem: Implement a shared stack with push/pop operations. 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define STACK_SIZE 10 9 | int stack[STACK_SIZE]; 10 | int top = -1; 11 | pthread_mutex_t stack_mutex = PTHREAD_MUTEX_INITIALIZER; 12 | 13 | void push(int val) 14 | { 15 | pthread_mutex_lock(&stack_mutex); 16 | if (top < STACK_SIZE - 1) 17 | { 18 | stack[++top] = val; 19 | printf("Pushed %d\n", val); 20 | } 21 | else 22 | { 23 | printf("Stack overflow!\n"); 24 | } 25 | pthread_mutex_unlock(&stack_mutex); 26 | } 27 | 28 | int pop() 29 | { 30 | pthread_mutex_lock(&stack_mutex); 31 | int val = -1; 32 | if (top >= 0) 33 | { 34 | val = stack[top--]; 35 | printf("Popped %d\n", val); 36 | } 37 | else 38 | { 39 | printf("Stack underflow!\n"); 40 | } 41 | pthread_mutex_unlock(&stack_mutex); 42 | return val; 43 | } 44 | 45 | void *stack_worker(void *arg) 46 | { 47 | for (int i = 0; i < 5; i++) 48 | { 49 | push(i); // Thread-safe push 50 | pop(); // Thread-safe pop 51 | } 52 | return NULL; 53 | } 54 | 55 | int main() 56 | { 57 | pthread_t t1, t2; 58 | pthread_create(&t1, NULL, stack_worker, NULL); 59 | pthread_create(&t2, NULL, stack_worker, NULL); 60 | pthread_join(t1, NULL); 61 | pthread_join(t2, NULL); 62 | 63 | pthread_mutex_destroy(&stack_mutex); 64 | return 0; 65 | } -------------------------------------------------------------------------------- /Lab 10/Ex10_FutureExample.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.concurrent.*; 3 | 4 | public class Ex10_FutureExample { 5 | public static void main(String[] args) { 6 | // Create a thread pool with a single thread 7 | ExecutorService executor = Executors.newSingleThreadExecutor(); 8 | 9 | // Submit a task to the executor that will return a result in the future 10 | Future future = executor.submit(() -> { 11 | Thread.sleep(1000); // Simulate long computation 12 | return 42; // Return the result 13 | }); 14 | 15 | System.out.println("Doing other work while waiting for result..."); 16 | 17 | try { 18 | // Retrieve the result (blocks if not ready) 19 | Integer result = future.get(); 20 | System.out.println("Got result: " + result); 21 | } catch (InterruptedException | ExecutionException e) { 22 | e.printStackTrace(); // Handle exceptions during computation 23 | } finally { 24 | executor.shutdown(); // Properly shut down the executor 25 | } 26 | } 27 | } 28 | /* 29 | 30 | Main points: 31 | ExecutorService runs tasks asynchronously (in the background). 32 | 33 | submit() starts a task and returns a Future, representing the pending result. 34 | 35 | future.get() waits (blocks) until the result is ready. 36 | 37 | Allows the program to do other work while waiting for the task to finish. 38 | 39 | Always shutdown the executor to free resources. 40 | 41 | */ -------------------------------------------------------------------------------- /Lab 11/Ex19_ThreadLocalExample2.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.*; 2 | import java.util.*; 3 | /* 4 | Alternative Approach (Using Future/Callable): For Ex17 5 | For more robust result handling, you could also use Callable with ExecutorService and Future: 6 | 7 | This second approach is more modern and provides better control over thread execution and result retrieval. 8 | */ 9 | public class Ex19_ThreadLocalExample2 { 10 | static ThreadLocal threadLocal = ThreadLocal.withInitial(() -> 0); 11 | 12 | public static void main(String[] args) throws InterruptedException, ExecutionException { 13 | ExecutorService executor = Executors.newFixedThreadPool(5); 14 | List> futures = new ArrayList<>(); 15 | 16 | for (int i = 0; i < 5; i++) { 17 | futures.add(executor.submit(new CallableTask())); 18 | } 19 | 20 | System.out.println("\nThread results after completion:"); 21 | for (int i = 0; i < futures.size(); i++) { 22 | System.out.println("Thread-" + (i+1) + ": " + futures.get(i).get()); 23 | } 24 | 25 | executor.shutdown(); 26 | } 27 | 28 | static class CallableTask implements Callable { 29 | @Override 30 | public Integer call() { 31 | int randomValue = (int)(Math.random() * 100); 32 | threadLocal.set(randomValue); 33 | System.out.println(Thread.currentThread().getName() + " running: " + threadLocal.get()); 34 | return threadLocal.get(); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Lab 07/Ex_12.c: -------------------------------------------------------------------------------- 1 | // using MUTEX 2 | // Multiple threads accessing shared memory location 3 | // With syrchronization to prevent 4 | // race condition 5 | 6 | #include 7 | #include 8 | #include // For exit() 9 | 10 | int shared_data = 0; // Shared resource 11 | pthread_mutex_t mutex; // Mutex to protect shared_data 12 | void *increment(void *arg) 13 | { 14 | for (int i = 0; i < 100000; i++) 15 | { 16 | pthread_mutex_lock(&mutex); // Lock the mutex 17 | shared_data++; // Access the shared resource 18 | pthread_mutex_unlock(&mutex); // Unlock the mutex 19 | } 20 | return NULL; 21 | } 22 | int main() 23 | { 24 | int num_threads = 5; 25 | pthread_t threads[5]; // Array to store thread IDs 26 | pthread_mutex_init(&mutex, NULL); // Initialize the mutex 27 | 28 | // Create threads 29 | for (int i = 0; i < num_threads; i++) 30 | { 31 | if (pthread_create(&threads[i], NULL, increment, NULL) != 0) 32 | { 33 | perror("Failed to create thread"); 34 | exit(EXIT_FAILURE); 35 | } 36 | } 37 | 38 | // Wait for all threads to finish 39 | for (int i = 0; i < num_threads; i++) 40 | { 41 | if (pthread_join(threads[i], NULL) != 0) 42 | { 43 | perror("Failed to join thread"); 44 | exit(EXIT_FAILURE); 45 | } 46 | } 47 | 48 | printf("Final value of shared_data: %d\n", shared_data); 49 | 50 | pthread_mutex_destroy(&mutex); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /Lab 07/Ex_16.c: -------------------------------------------------------------------------------- 1 | // Semaphore: Example 2 2 | 3 | #include 4 | #include 5 | #include 6 | #include // For sleep function 7 | 8 | #define THREAD_COUNT 5 9 | // sem_t semaphore; 10 | void *thread_function(void *arg) 11 | { 12 | int id = *(int *)arg; 13 | // sem_wait(&semaphore); // Decrement the semaphore 14 | printf("Thread %d is accessing the resource\n", id); 15 | sleep(1); // Simulate work 16 | printf("Thread %d is releasing the resource\n", id); 17 | // sem_post(&semaphore); // Increment the semaphore 18 | return NULL; 19 | } 20 | int main() 21 | { 22 | pthread_t threads[THREAD_COUNT]; 23 | int thread_ids[THREAD_COUNT]; 24 | // sem_init(&semaphore, 0, 2); // Initialize semaphore with a value of 2 25 | // Create threads 26 | for (int i = 0; i < THREAD_COUNT; i++) 27 | { 28 | thread_ids[i] = i; 29 | pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]); 30 | } 31 | // Wait for threads to finish 32 | for (int i = 0; i < THREAD_COUNT; i++) 33 | { 34 | pthread_join(threads[i], NULL); 35 | } 36 | // sem_destroy(&semaphore); // Destroy the semaphore 37 | return 0; 38 | } 39 | 40 | /* 41 | Explanation: 42 | - The semaphore is initialized with a value of 2, meaning only 2 43 | threads can access the resource at a time. 44 | - sem_wait(&semaphore) decrements the semaphore, and if the value is 0, the thread waits. 45 | - sem_post(&semaphore) increments the semaphore, allowing another thread to access the resource. 46 | 47 | */ -------------------------------------------------------------------------------- /Lab 11/Ex16_CountdownLatchExample.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.CountDownLatch; 2 | 3 | /** 4 | * Demonstrates CountDownLatch usage to make main thread wait for worker threads. 5 | */ 6 | public class Ex16_CountdownLatchExample { 7 | public static void main(String[] args) throws InterruptedException { 8 | // Initialize latch with count=3 (must count down 3 times before releasing) 9 | CountDownLatch latch = new CountDownLatch(3); 10 | 11 | // Worker task that counts down when done 12 | Runnable worker = () -> { 13 | System.out.println(Thread.currentThread().getName() + " is working..."); 14 | try { 15 | Thread.sleep(500); // Simulate work 16 | } catch (Exception ignored) {} 17 | System.out.println(Thread.currentThread().getName() + " finished."); 18 | latch.countDown(); // Decrement latch count 19 | }; 20 | 21 | // Start 3 worker threads 22 | for (int i = 0; i < 3; i++) new Thread(worker).start(); 23 | 24 | latch.await(); // Main thread blocks until latch reaches 0 25 | System.out.println("All workers are done. Main continues."); 26 | } 27 | } 28 | /* 29 | Key Points: 30 | Synchronization Tool: CountDownLatch makes threads wait until a count reaches zero 31 | Worker Pattern: Main thread waits for N workers to finish 32 | One-Time Use: Latch cannot be reset after count reaches zero 33 | Non-Blocking Workers: Workers proceed immediately after countDown() 34 | Common Use Cases: Server startup, parallel task coordination 35 | */ -------------------------------------------------------------------------------- /Lab 05/Lab5 Test.asm: -------------------------------------------------------------------------------- 1 | ;cmp 2 | ;FLags; ZF, CF, SF, OF 3 | 4 | ; conditional JUMP 5 | ;unsigend: ja, jb, je, jne, jae, jbe 6 | ; signed: jg, jl, je, jne, jge, jle 7 | ; adc: add with carry 8 | ; jc: jump if carry 9 | ; jnc: jump not carry 10 | ; printn 'message' 11 | 12 | ; putc 'A' 13 | 14 | ; Display using video mode 15 | 16 | include 'emu8086.inc' 17 | org 100h 18 | 19 | ;mov al, -10 20 | ;mov bl, 5 21 | ; 22 | ;cmp al, bl ; al - bl 23 | ;jg L ; al > bl 24 | ; print 'AL is less than or equal to BL' 25 | ;jmp exit 26 | ;L: 27 | ; print 'AL is greater than BL' 28 | ; 29 | ;exit: 30 | ;ret 31 | 32 | 33 | ;mov al, array[0] 34 | ;mov bl, array[1] 35 | ;cmp al, bl 36 | ;ja L ; al > bl 37 | ;mov max, bl 38 | ;mov min, al 39 | ;jmp exit 40 | ;L: 41 | ; mov max, al 42 | ; mov min, bl 43 | ;exit: 44 | ;ret 45 | ;array db 30, 70 46 | ;min db ? 47 | ;max db ? 48 | 49 | mov al, 127 50 | mov bl, 1 51 | 52 | add al, bl 53 | ;jnc L ; jnc = jump if not carry 54 | ; adc ah, 0 ; ah = ah + 0 + CF ; adc = add with carry 55 | ;L: 56 | ;mov sum, ax 57 | 58 | ret 59 | sum dw ? 60 | 61 | 62 | ;mov al, 0 63 | ;mov cx, 5 64 | ;mov si, 0 65 | ;start: 66 | ; mov bl, array[si] 67 | ; add al, bl 68 | ; ;jnc L 69 | ; adc ah, 0 ; ah = ah + 0 + CF 70 | ; inc si 71 | ;loop start 72 | ; 73 | ;mov sum, ax 74 | ; 75 | ;printn 'ALL is done' 76 | ; 77 | ;ret 78 | ;array db 255, 20 , 10, 255, 20 79 | ;sum dw ? 80 | 81 | 82 | ;array 10, 5, 7, 3, 41, 9 find max, min in one Loop 83 | ;array -10, +5, +17, -3, -41, +9 find max, min in one Loop 84 | 85 | ; given 2 Arrays 1 3 and 4 5 ; required to merge into one sorted array -------------------------------------------------------------------------------- /Lab 10/Ex04_SynchronizedExample.java: -------------------------------------------------------------------------------- 1 | 2 | public class Ex04_SynchronizedExample { 3 | private int count = 0; 4 | 5 | public synchronized void increment() { 6 | count++; 7 | } 8 | 9 | public void doWork() { 10 | Thread t1 = new Thread(() -> { 11 | for (int i = 0; i < 10000; i++) { 12 | increment(); 13 | } 14 | }); 15 | 16 | Thread t2 = new Thread(() -> { 17 | for (int i = 0; i < 10000; i++) { 18 | increment(); 19 | } 20 | }); 21 | 22 | t1.start(); 23 | t2.start(); 24 | 25 | try { 26 | t1.join(); 27 | t2.join(); 28 | } catch (InterruptedException e) { 29 | e.printStackTrace(); 30 | } 31 | 32 | System.out.println("Count is: " + count); 33 | } 34 | 35 | public static void main(String[] args) { 36 | new Ex04_SynchronizedExample().doWork(); 37 | } 38 | } 39 | /* 40 | This Java code demonstrates using `synchronized` to safely update a shared variable (`count`) from multiple threads. 41 | 42 | **Summary:** 43 | - `count` starts at 0. 44 | - `increment()` is a synchronized method, meaning **only one thread can execute it at a time**, preventing race conditions. 45 | - `doWork()` creates two threads (`t1` and `t2`), each calling `increment()` **10,000 times**. 46 | - After both threads finish (using `join()`), it prints the final value of `count`, which should correctly be `20000`. 47 | 48 | **Main point:** 49 | `synchronized` ensures that updating `count` is thread-safe, avoiding issues like lost updates. 50 | 51 | 52 | */ -------------------------------------------------------------------------------- /Lab 06/Ex_03.c: -------------------------------------------------------------------------------- 1 | /* Create 3 Threads 2 | pthread_self() used to get thread id to identify each thread 3 | * File: multi_thread_no_args.c 4 | * Description: Creates 3 threads without passing any arguments. Each thread prints 5 | * a message with its logical ID (based on loop counter). The main thread 6 | * waits for all threads to finish before printing its own message. 7 | */ 8 | 9 | #include // For thread management 10 | #include // For I/O operations 11 | #include // For exit() 12 | 13 | // Function executed by each thread 14 | // arg: Unused (no arguments passed) 15 | // Returns: NULL 16 | void *thread_function(void *arg) 17 | { 18 | // Get the thread ID of the current thread 19 | pthread_t tid = pthread_self(); 20 | printf("Hello from thread! Thread ID: %lu \n", (unsigned long)tid); 21 | return NULL; // Indicate successful completion 22 | } 23 | 24 | // Main function: Creates 5 threads, waits for them, and prints a message 25 | // Returns: 0 on success 26 | int main() 27 | { 28 | pthread_t thread1, thread2, thread3; // to store thread IDs 29 | 30 | // Create 5 threads 31 | pthread_create(&thread1, NULL, thread_function, NULL); 32 | pthread_create(&thread2, NULL, thread_function, NULL); 33 | pthread_create(&thread3, NULL, thread_function, NULL); 34 | 35 | // Wait for all 5 threads to finish 36 | pthread_join(thread1, NULL); 37 | pthread_join(thread2, NULL); 38 | pthread_join(thread3, NULL); 39 | 40 | // Print message from the main thread 41 | printf("Main thread finished.\n"); 42 | 43 | return 0; // Program ends successfully 44 | } -------------------------------------------------------------------------------- /Lab 10/TaskThreadDemo.java: -------------------------------------------------------------------------------- 1 | public class TaskThreadDemo { 2 | public static void main(String[] args) { 3 | // Create tasks 4 | Runnable printA = new PrintChar('a', 1000); 5 | Runnable printB = new PrintChar('b', 1000); 6 | Runnable print100 = new PrintNum(100); 7 | 8 | // Create threads 9 | Thread thread1 = new Thread(printA); 10 | Thread thread2 = new Thread(printB); 11 | Thread thread3 = new Thread(print100); 12 | 13 | // Start threads 14 | thread1.start(); 15 | thread2.start(); 16 | thread3.start(); 17 | } 18 | } 19 | 20 | // The task for printing a specified character in specified times 21 | class PrintChar implements Runnable { 22 | private char charToPrint; // The character to print 23 | private int times; // The times to repeat 24 | 25 | /** Construct a task with specified character and number of 26 | * times to print the character 27 | */ 28 | public PrintChar(char c, int t) { 29 | charToPrint = c; 30 | times = t; 31 | } 32 | 33 | /** Override the run() method to tell the system 34 | * what the task to perform 35 | */ 36 | public void run() { 37 | for (int i = 0; i < times; i++) { 38 | System.out.print(charToPrint); 39 | } 40 | } 41 | } 42 | 43 | // The task class for printing number from 1 to n for a given n 44 | class PrintNum implements Runnable { 45 | private int lastNum; 46 | 47 | /** Construct a task for printing 1, 2, ... i */ 48 | public PrintNum(int n) { 49 | lastNum = n; 50 | } 51 | 52 | /** Tell the thread how to run */ 53 | public void run() { 54 | for (int i = 1; i <= lastNum; i++) { 55 | System.out.print(" " + i); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Lab 07/Ex_07.c: -------------------------------------------------------------------------------- 1 | // passing multiple values 2 | 3 | #include // Include the pthread library 4 | #include // Standard I/O library 5 | #include // For sleep function 6 | 7 | // Define a structure to hold multiple parameters 8 | typedef struct 9 | { 10 | int start; // Start number 11 | int end; // End number 12 | char *message; // Message to print 13 | } ThreadData; 14 | 15 | // Function to be executed by the thread 16 | void *print_numbers_with_message(void *arg) 17 | { 18 | // Cast the argument to a ThreadData pointer 19 | ThreadData *data = (ThreadData *)arg; 20 | 21 | // Print the numbers from start to end with a message 22 | for (int i = data->start; i <= data->end; i++) 23 | { 24 | printf("Thread ID: %lu message: %s %d\n", (unsigned long)pthread_self(), data->message, i); 25 | sleep(1); // Sleep for 1 second to simulate work 26 | } 27 | 28 | return NULL; // Return null when done 29 | } 30 | 31 | int main() 32 | { 33 | pthread_t thread_id; // Declare a thread identifier 34 | 35 | // Initialize the thread data 36 | ThreadData data; 37 | data.start = 1; 38 | data.end = 5; 39 | data.message = "Welcome"; 40 | 41 | // Create the thread 42 | if (pthread_create(&thread_id, NULL, print_numbers_with_message, &data) != 0) 43 | { 44 | perror("Failed to create thread"); 45 | return 1; 46 | } 47 | 48 | // Wait for the thread to complete 49 | if (pthread_join(thread_id, NULL) != 0) 50 | { 51 | perror("Failed to join thread"); 52 | return 1; 53 | } 54 | 55 | printf("Main thread: All tasks are complete.\n"); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /Lab 07/Ex_14.c: -------------------------------------------------------------------------------- 1 | // Bank Account Simulation (Intermediate) 2 | // Problem: Safely manage concurrent deposits/withdrawals from a shared bank account. 3 | // mutex lock with each account 4 | 5 | #include 6 | #include 7 | 8 | typedef struct 9 | { 10 | double balance; 11 | pthread_mutex_t lock; 12 | } BankAccount; 13 | 14 | void deposit(BankAccount *acc, double amount) 15 | { 16 | pthread_mutex_lock(&acc->lock); 17 | acc->balance += amount; 18 | printf("Deposited $%.2f, new balance: $%.2f\n", amount, acc->balance); 19 | pthread_mutex_unlock(&acc->lock); 20 | } 21 | 22 | void withdraw(BankAccount *acc, double amount) 23 | { 24 | pthread_mutex_lock(&acc->lock); 25 | if (acc->balance >= amount) 26 | { 27 | acc->balance -= amount; 28 | printf("Withdrew $%.2f, new balance: $%.2f\n", amount, acc->balance); 29 | } 30 | else 31 | { 32 | printf("Failed to withdraw $%.2f (insufficient funds)\n", amount); 33 | } 34 | pthread_mutex_unlock(&acc->lock); 35 | } 36 | 37 | void *account_activity(void *arg) 38 | { 39 | BankAccount *acc = (BankAccount *)arg; 40 | for (int i = 0; i < 5; i++) 41 | { 42 | deposit(acc, 100.50); 43 | withdraw(acc, 75.25); 44 | } 45 | return NULL; 46 | } 47 | 48 | int main() 49 | { 50 | BankAccount acc = {.balance = 500.00, .lock = PTHREAD_MUTEX_INITIALIZER}; 51 | pthread_t t1, t2; 52 | 53 | pthread_create(&t1, NULL, account_activity, &acc); 54 | pthread_create(&t2, NULL, account_activity, &acc); 55 | 56 | pthread_join(t1, NULL); 57 | pthread_join(t2, NULL); 58 | 59 | printf("Final balance: $%.2f\n", acc.balance); 60 | 61 | pthread_mutex_destroy(&acc.lock); 62 | 63 | return 0; 64 | } -------------------------------------------------------------------------------- /Lab 06/Ex_02.c: -------------------------------------------------------------------------------- 1 | /* More than one thread 2 | * File: Ex_02.c 3 | * Description: This program demonstrates the basic usage of POSIX threads (pthreads) in C. 4 | * It creates a new thread that prints a message, and the main thread waits 5 | * for the newly created thread to finish before printing its own message. 6 | * The program illustrates thread creation, thread execution, and thread joining. 7 | */ 8 | 9 | #include // Include the pthread library for thread management 10 | #include // Include the standard I/O library for input/output operations 11 | 12 | // Function: thread_function 13 | // Description: This function is executed by the new thread when it starts. 14 | // It prints a message to the console and then exits. 15 | // Parameters: 16 | // - arg: A pointer to the argument passed to the thread (unused in this example). 17 | // Returns: NULL, as the function does not need to return any value. 18 | void *thread_function(void *arg) 19 | { 20 | printf("Hello from thread!\n"); // Print a message from the new thread 21 | return NULL; // Return NULL to indicate successful completion 22 | } 23 | 24 | int main() 25 | { 26 | pthread_t thread1, thread2; // two thread identifiers 27 | 28 | // creat two threads 29 | pthread_create(&thread1, NULL, thread_function, NULL); 30 | pthread_create(&thread2, NULL, thread_function, NULL); 31 | 32 | // wait for the threads to finish their work 33 | pthread_join(thread1, NULL); 34 | pthread_join(thread1, NULL); 35 | 36 | // Print a message from the main thread after the new thread has finished 37 | printf("Main thread finished.\n"); 38 | 39 | return 0; // Return 0 to indicate successful program termination 40 | } -------------------------------------------------------------------------------- /Lab 10/Ex09_ExecutorDemo.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.*; 2 | 3 | public class Ex09_ExecutorDemo { 4 | public static void main(String[] args) { 5 | // Create a fixed thread pool with maximum three threads 6 | ExecutorService executor = Executors.newFixedThreadPool(3); 7 | 8 | // Submit runnable tasks to the executor 9 | executor.execute(new Print_Char('a', 100)); 10 | executor.execute(new Print_Char('b', 100)); 11 | executor.execute(new Print_Num(100)); 12 | 13 | // Shut down the executor 14 | executor.shutdown(); 15 | } 16 | } 17 | // The task for printing a specified character in specified times 18 | class Print_Char implements Runnable { 19 | private char charToPrint; // The character to print 20 | private int times; // The times to repeat 21 | 22 | /** Construct a task with specified character and number of 23 | * times to print the character 24 | */ 25 | public Print_Char(char c, int t) { 26 | charToPrint = c; 27 | times = t; 28 | } 29 | 30 | /** Override the run() method to tell the system 31 | * what the task to perform 32 | */ 33 | public void run() { 34 | for (int i = 0; i < times; i++) { 35 | System.out.print(charToPrint); 36 | } 37 | } 38 | } 39 | 40 | // The task class for printing number from 1 to n for a given n 41 | class Print_Num implements Runnable { 42 | private int lastNum; 43 | 44 | /** 45 | * Construct a task for printing 1, 2, ... i 46 | */ 47 | public Print_Num(int n) { 48 | lastNum = n; 49 | } 50 | 51 | /** 52 | * Tell the thread how to run 53 | */ 54 | public void run() { 55 | for (int i = 1; i <= lastNum; i++) { 56 | System.out.print(" " + i); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Lab 10/Ex06_SemaphoreExample.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.concurrent.Semaphore; 3 | 4 | public class Ex06_SemaphoreExample { 5 | private final Semaphore semaphore = new Semaphore(3); // Allow 3 threads to access the resource simultaneously 6 | private int activeThreads = 0; // Counter for currently active threads inside the critical section 7 | 8 | public void accessResource() { 9 | try { 10 | semaphore.acquire(); // Try to acquire a permit (wait if none available) 11 | 12 | // Start of critical section 13 | synchronized (this) { // Synchronize to safely update activeThreads 14 | activeThreads++; 15 | System.out.println(Thread.currentThread().getName() + 16 | " acquired permit. Active threads: " + activeThreads); 17 | } 18 | 19 | Thread.sleep(2000); // Simulate time taken to use the resource 20 | 21 | } catch (InterruptedException e) { 22 | e.printStackTrace(); 23 | } finally { 24 | synchronized (this) { // Synchronize to safely update activeThreads before leaving 25 | activeThreads--; 26 | System.out.println(Thread.currentThread().getName() + 27 | " releasing permit. Active threads: " + activeThreads); 28 | } 29 | semaphore.release(); // Release the permit for other threads 30 | } 31 | } 32 | 33 | public static void main(String[] args) { 34 | Ex06_SemaphoreExample example = new Ex06_SemaphoreExample(); 35 | 36 | // Create and start 10 threads trying to access the resource 37 | for (int i = 0; i < 10; i++) { 38 | new Thread(() -> example.accessResource()).start(); 39 | } 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /Lab 06/Ex_04.c: -------------------------------------------------------------------------------- 1 | /* 2 | COMPILE: gcc -pthread Ex_02.c 3 | RUN: a.exe 4 | */ 5 | 6 | /* 7 | * File: multi_thread_no_args.c 8 | * Description: Creates 5 threads without passing any arguments. Each thread prints 9 | * a message. The main thread 10 | * waits for all threads to finish before printing its own message. 11 | */ 12 | 13 | #include // For thread management 14 | #include // For I/O operations 15 | #include // For exit() 16 | 17 | // Function executed by each thread 18 | // arg: Unused (no arguments passed) 19 | // Returns: NULL 20 | void *thread_function(void *arg) 21 | { 22 | printf("Hello from thread! Thread ID: %lu \n", (unsigned long)pthread_self()); 23 | return NULL; // Indicate successful completion 24 | } 25 | 26 | // Main function: Creates 5 threads, waits for them, and prints a message 27 | // Returns: 0 on success 28 | int main() 29 | { 30 | pthread_t threads[5]; // Array to store thread IDs 31 | 32 | // Create 5 threads 33 | for (int i = 0; i < 5; i++) 34 | { 35 | if (pthread_create(&threads[i], NULL, thread_function, NULL) != 0) 36 | /* used for error handling when creating a thread */ 37 | { 38 | perror("Failed to create thread"); 39 | exit(EXIT_FAILURE); 40 | } 41 | } 42 | 43 | // Wait for all 5 threads to finish 44 | for (int i = 0; i < 5; i++) 45 | { 46 | if (pthread_join(threads[i], NULL) != 0) 47 | /* used for error handling when waiting a thread */ 48 | { 49 | perror("Failed to join thread"); 50 | exit(EXIT_FAILURE); 51 | } 52 | } 53 | 54 | // Print message from the main thread 55 | printf("Main thread finished.\n"); 56 | 57 | return 0; // Program ends successfully 58 | } -------------------------------------------------------------------------------- /Lab 07/Ex_09.c: -------------------------------------------------------------------------------- 1 | // retrieve value from Thread function 2 | 3 | #include 4 | #include 5 | #include 6 | #include // For exit() 7 | 8 | // Global variable (shared between threads): 9 | int i = 2; 10 | 11 | /** 12 | * Thread function that modifies a global variable and returns its address. 13 | * @param p Pointer to an integer passed from the main thread. 14 | * @return void* (Pointer to the modified global variable `i`). 15 | */ 16 | void *foo(void *p) 17 | { 18 | // Print the value received from the main thread: 19 | printf("Value received as argument in starting routine: "); 20 | printf("%i\n", *(int *)p); 21 | 22 | // Modify the global variable: 23 | i = i * 10; 24 | 25 | // Return the address of the modified global variable: 26 | pthread_exit(&i); 27 | } 28 | 29 | int main(void) 30 | { 31 | // Thread identifier: 32 | pthread_t id; 33 | 34 | // Local variable passed to the thread: 35 | int j = 1; 36 | 37 | // Create a new thread: 38 | if (pthread_create(&id, NULL, foo, &j) != 0) 39 | /* Error handling if thread creation fails */ 40 | { 41 | perror("Failed to create thread"); 42 | exit(EXIT_FAILURE); 43 | } 44 | 45 | // Pointer to store the returned value from the thread: 46 | int *ptr; 47 | 48 | // Wait for the thread to finish and get the returned value: 49 | if (pthread_join(id, (void **)&ptr) != 0) // Check pthread_join.md for more details 50 | /* Error handling if thread joining fails */ 51 | { 52 | perror("Failed to join thread"); 53 | exit(EXIT_FAILURE); 54 | } 55 | 56 | // Print the value received from the child thread: 57 | printf("Value received by parent from child: "); 58 | printf("%i\n", *ptr); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /Lab 10/Ex05_SimpleLockExample.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.concurrent.locks.Lock; 3 | import java.util.concurrent.locks.ReentrantLock; 4 | 5 | public class Ex05_SimpleLockExample { 6 | private final Lock lock = new ReentrantLock(); 7 | private int counter = 0; 8 | 9 | public void increment() { 10 | lock.lock(); // Acquire the lock 11 | try { 12 | counter++; // Critical section 13 | System.out.println(Thread.currentThread().getName() + ": Counter = " + counter); 14 | } finally { 15 | lock.unlock(); // Always release the lock in finally block 16 | } 17 | } 18 | 19 | public static void main(String[] args) { 20 | Ex05_SimpleLockExample example = new Ex05_SimpleLockExample(); 21 | 22 | // Create 3 threads that increment the counter 23 | for (int i = 0; i < 3; i++) { 24 | new Thread(() -> { 25 | for (int j = 0; j < 5; j++) { 26 | example.increment(); 27 | try { 28 | Thread.sleep(100); // Simulate some work 29 | } catch (InterruptedException e) { 30 | e.printStackTrace(); 31 | } 32 | } 33 | }).start(); 34 | } 35 | } 36 | } 37 | /* 38 | Key Points: 39 | - Lock Creation: Lock lock = new ReentrantLock(); 40 | - Acquiring Lock: lock.lock(); (blocks until lock is available) 41 | - Releasing Lock: lock.unlock(); (must be in finally block) 42 | - Critical Section: The code between lock() and unlock() 43 | 44 | Why Use Lock Instead of synchronized? 45 | - More flexible (can try to acquire lock with timeout) 46 | - Can be acquired in one method and released in another 47 | - Supports multiple Condition objects 48 | - Better performance in some cases 49 | */ -------------------------------------------------------------------------------- /Lab 07/Ex_08.c: -------------------------------------------------------------------------------- 1 | #include // Include the pthread library 2 | #include // Standard I/O library 3 | #include // For sleep function 4 | 5 | // Define a structure to hold multiple parameters 6 | typedef struct 7 | { 8 | int thread_id; // Thread identifier 9 | char *thread_name; // Thread name 10 | } ThreadData; 11 | 12 | // Function to be executed by each thread 13 | void *print_thread_info(void *arg) 14 | { 15 | // Cast the argument to a ThreadData pointer 16 | ThreadData *data = (ThreadData *)arg; 17 | 18 | // Print the thread ID and name 19 | printf("Thread ID: %d, Thread Name: %s\n", data->thread_id, data->thread_name); 20 | 21 | // Simulate work 22 | //sleep(1); // Sleep for 1 second 23 | 24 | return NULL; // Return null when done 25 | } 26 | 27 | int main() 28 | { 29 | pthread_t threads[3]; // Array to hold thread identifiers 30 | ThreadData thread_data[3]; // Array to hold thread data for each thread 31 | 32 | // Initialize thread data 33 | thread_data[0].thread_id = 1; 34 | thread_data[0].thread_name = "Alpha"; 35 | 36 | thread_data[1].thread_id = 2; 37 | thread_data[1].thread_name = "Beta"; 38 | 39 | thread_data[2].thread_id = 3; 40 | thread_data[2].thread_name = "Gamma"; 41 | 42 | // Create the threads 43 | for (int i = 0; i < 3; i++) 44 | { 45 | if (pthread_create(&threads[i], NULL, print_thread_info, &thread_data[i]) != 0) 46 | { 47 | perror("Failed to create thread"); 48 | return 1; 49 | } 50 | } 51 | 52 | // Wait for all threads to complete 53 | for (int i = 0; i < 3; i++) 54 | { 55 | if (pthread_join(threads[i], NULL) != 0) 56 | { 57 | perror("Failed to join thread"); 58 | return 1; 59 | } 60 | } 61 | 62 | printf("Main thread: All tasks are complete.\n"); 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /Lab 06/Ex_05.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: multi_thread.c 3 | * Description: 4 | * Creates 5 threads, each printing a message. 5 | * passing a value to the load function 6 | * The main thread waits 7 | * for all threads to finish before printing its own message. 8 | */ 9 | 10 | #include // For thread management 11 | #include // For I/O operations 12 | #include // For exit() 13 | 14 | // Function executed by each thread 15 | // arg: Pointer to the thread's unique ID (cast to int) 16 | // Returns: NULL 17 | void *thread_function(void *arg) 18 | { 19 | int thread_index = *(int *)arg; // Cast and dereference the argument to get the thread ID 20 | printf("Hello from thread %d!\n", thread_index); // Print message with thread ID 21 | return NULL; // Indicate successful completion 22 | } 23 | 24 | // Main function: Creates 5 threads, waits for them, and prints a message 25 | // Returns: 0 on success 26 | int main() 27 | { 28 | pthread_t threads[5]; // Array to store thread IDs 29 | int thread_index[5]; // Array to store thread index 30 | 31 | // Create 5 threads 32 | for (int i = 0; i < 5; i++) 33 | { 34 | thread_index[i] = i + 1; // Assign thread ID (1 to 5) 35 | // Create a thread and pass the address of thread_args[i] as the argument 36 | if (pthread_create(&threads[i], NULL, thread_function, &thread_index[i]) != 0) 37 | { 38 | perror("Failed to create thread"); 39 | exit(EXIT_FAILURE); 40 | } 41 | } 42 | 43 | // Wait for all 5 threads to finish 44 | for (int i = 0; i < 5; i++) 45 | { 46 | if (pthread_join(threads[i], NULL) != 0) 47 | { 48 | perror("Failed to join thread"); 49 | exit(EXIT_FAILURE); 50 | } 51 | } 52 | 53 | // Print message from the main thread 54 | printf("Main thread finished.\n"); 55 | 56 | return 0; // Program ends successfully 57 | } -------------------------------------------------------------------------------- /Lab 10/Ex07_LockConditionExample.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.concurrent.locks.*; 3 | 4 | public class Ex07_LockConditionExample { 5 | private final Lock lock = new ReentrantLock(); // Lock to control access 6 | private final Condition condition = lock.newCondition(); // Condition for signaling between threads 7 | private boolean ready = false; // Shared flag indicating if the producer has produced 8 | 9 | public void producer() { 10 | lock.lock(); // Acquire the lock before accessing shared data 11 | try { 12 | System.out.println("Producer is producing..."); 13 | Thread.sleep(2000); // Simulate some work being done 14 | ready = true; // Mark that production is done 15 | condition.signal(); // Signal the waiting consumer 16 | System.out.println("Producer signaled."); 17 | } catch (InterruptedException e) { 18 | e.printStackTrace(); 19 | } finally { 20 | lock.unlock(); // Always release the lock 21 | } 22 | } 23 | 24 | public void consumer() { 25 | lock.lock(); // Acquire the lock before accessing shared data 26 | try { 27 | while (!ready) { // Wait until the producer signals 28 | System.out.println("Consumer waiting..."); 29 | condition.await(); // Wait (release lock temporarily) 30 | } 31 | System.out.println("Consumer consumed."); // Proceed after being signaled 32 | } catch (InterruptedException e) { 33 | e.printStackTrace(); 34 | } finally { 35 | lock.unlock(); // Always release the lock 36 | } 37 | } 38 | 39 | public static void main(String[] args) { 40 | Ex07_LockConditionExample example = new Ex07_LockConditionExample(); 41 | 42 | // Start the consumer and producer in separate threads 43 | new Thread(() -> example.consumer()).start(); 44 | new Thread(() -> example.producer()).start(); 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /Lab 07/Ex_10.c: -------------------------------------------------------------------------------- 1 | // Passing & Retrieving Multiple Values via Struct 2 | #include 3 | #include 4 | #include 5 | 6 | // Struct to hold input and output data 7 | typedef struct 8 | { 9 | int number; // Input value 10 | int squared; // Output: number² 11 | int cubed; // Output: number³ 12 | char message[50]; // Output: Modified message 13 | } ThreadData; 14 | 15 | // Thread function: computes square, cube, and modifies message 16 | void *compute_values(void *arg) 17 | { 18 | ThreadData *data = (ThreadData *)arg; 19 | 20 | // Compute square and cube 21 | data->squared = data->number * data->number; 22 | data->cubed = data->number * data->number * data->number; 23 | 24 | // Modify the message using (snprintf) 25 | // Safe & formatted // Ensure null-termination 26 | snprintf(data->message, sizeof(data->message), 27 | "Thread modifidded this! (Original: %d)", 28 | data->number); 29 | 30 | // Return the modified struct (as a void pointer) 31 | pthread_exit((void *)data); 32 | } 33 | 34 | int main() 35 | { 36 | pthread_t thread_id; 37 | ThreadData data = { 38 | .number = 3, // Input value 39 | .squared = 0, // Will be updated by thread 40 | .cubed = 0, // Will be updated by thread 41 | .message = "Initial message"}; 42 | 43 | // Create thread and pass the struct 44 | if (pthread_create(&thread_id, NULL, compute_values, &data) != 0) 45 | { 46 | perror("Failed to create thread"); 47 | return 1; 48 | } 49 | 50 | // Pointer to receive the returned struct 51 | ThreadData *result; 52 | 53 | // Wait for thread and get the modified struct 54 | if (pthread_join(thread_id, (void **)&result) != 0) 55 | { 56 | perror("Failed to join thread"); 57 | return 1; 58 | } 59 | 60 | // Print the results 61 | printf("Original number: %d\n", result->number); 62 | printf("Squared: %d\n", result->squared); 63 | printf("Cubed: %d\n", result->cubed); 64 | printf("Message: %s\n", result->message); 65 | 66 | return 0; 67 | } -------------------------------------------------------------------------------- /Info/Conditional Jumps After CMP.md: -------------------------------------------------------------------------------- 1 | In x86 assembly, comparison instructions are used to compare two operands and set flags accordingly. The choice of comparison instructions depends on whether the operands are **signed** or **unsigned**. Here are the most common comparison instructions: 2 | 3 | ### 1. **CMP (Compare)** 4 | - `CMP dest, src` 5 | - Subtracts `src` from `dest` but **does not store the result**—only updates the CPU flags. 6 | - Used for both **signed** and **unsigned** comparisons. 7 | 8 | ### 2. **TEST (Bitwise AND)** 9 | - `TEST dest, src` 10 | - Performs a bitwise AND between `dest` and `src` and updates the flags. 11 | - Typically used for checking if a value is zero or if certain bits are set. 12 | 13 | --- 14 | 15 | ### **Conditional Jumps After CMP** 16 | Once `CMP` is used, conditional jumps can be used based on the signedness of operands. 17 | 18 | #### **For Unsigned Comparisons** 19 | - `JA` (Jump if Above) → Equivalent to `>` (unsigned) → `CF=0` and `ZF=0` 20 | - `JAE` (Jump if Above or Equal) → Equivalent to `>=` (unsigned) → `CF=0` 21 | - `JB` (Jump if Below) → Equivalent to `<` (unsigned) → `CF=1` 22 | - `JBE` (Jump if Below or Equal) → Equivalent to `<=` (unsigned) → `CF=1 or ZF=1` 23 | 24 | #### **For Signed Comparisons** 25 | - `JG` (Jump if Greater) → Equivalent to `>` (signed) → `ZF=0 and SF=OF` 26 | - `JGE` (Jump if Greater or Equal) → Equivalent to `>=` (signed) → `SF=OF` 27 | - `JL` (Jump if Less) → Equivalent to `<` (signed) → `SF≠OF` 28 | - `JLE` (Jump if Less or Equal) → Equivalent to `<=` (signed) → `ZF=1 or SF≠OF` 29 | 30 | #### **For Equality Checks (Used in Both Signed and Unsigned Comparisons)** 31 | - `JE` (Jump if Equal) → `ZF=1` 32 | - `JNE` (Jump if Not Equal) → `ZF=0` 33 | 34 | --- 35 | 36 | ### **Example** 37 | #### **Unsigned Comparison (`JA, JB`)** 38 | ```assembly 39 | mov eax, 10 40 | cmp eax, 5 41 | ja above_label ; Jumps because 10 > 5 (unsigned) 42 | ``` 43 | 44 | #### **Signed Comparison (`JG, JL`)** 45 | ```assembly 46 | mov eax, -10 47 | cmp eax, 5 48 | jl less_label ; Jumps because -10 < 5 (signed) 49 | ``` 50 | 51 | Would you like more details on a specific scenario? -------------------------------------------------------------------------------- /Lab 03/Ex_14.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: Ex_14.asm 3 | ; Date: Day-Month-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | org 100h ; Set the origin (starting address) of the program to 100h (typical for .COM files) 7 | 8 | Data db 25h, 4fh, 85h, 1fh, 2bh, 0c4h ; Define the 'data' array with the given byte values 9 | copy db 6 dup(?) ; Define the 'copy' array with 6 uninitialized elements 10 | 11 | ; Direct Addressing Method 12 | mov al, data[0] 13 | mov copy[0], al 14 | ; ; ; 15 | ; ; ; 16 | 17 | ; index addressing method 18 | mov si, 0 ; Initialize the SI register (index register) to 0 19 | mov al, data[si] ; Move the first element of the 'data' array (25h) into the AL register 20 | mov copy[si], al ; Move the value in AL (25h) into the first element of the 'copy' array 21 | 22 | inc si ; Increment SI to point to the next index (SI = 1) 23 | mov al, data[si] ; Move the second element of the 'data' array (4Fh) into the AL register 24 | mov copy[si], al ; Move the value in AL (4Fh) into the second element of the 'copy' array 25 | 26 | inc si ; Increment SI to point to the next index (SI = 2) 27 | mov al, data[si] ; Move the third element of the 'data' array (85h) into the AL register 28 | mov copy[si], al ; Move the value in AL (85h) into the third element of the 'copy' array 29 | 30 | inc si ; Increment SI to point to the next index (SI = 3) 31 | mov al, data[si] ; Move the fourth element of the 'data' array (1Fh) into the AL register 32 | mov copy[si], al ; Move the value in AL (1Fh) into the fourth element of the 'copy' array 33 | 34 | inc si ; Increment SI to point to the next index (SI = 4) 35 | mov al, data[si] ; Move the fifth element of the 'data' array (2Bh) into the AL register 36 | mov copy[si], al ; Move the value in AL (2Bh) into the fifth element of the 'copy' array 37 | 38 | inc si ; Increment SI to point to the next index (SI = 5) 39 | mov al, data[si] ; Move the sixth element of the 'data' array (0C4h) into the AL register 40 | mov copy[si], al ; Move the value in AL (0C4h) into the sixth element of the 'copy' array 41 | 42 | ret ; Return from the program (end execution) 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Lab 05/Ex_40.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: .asm 3 | ; Date: Day-Month-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | org 100h ; Set the origin address to 100h for the program 7 | 8 | mov cx, 7 ; Initialize counter (CX) to 7 for 8 elements (0 to 7) 9 | mov si, 0 ; Initialize source index (SI) to 0 to start from the first element 10 | mov al, degrees[si] ; Load the first element (degrees[0]) into AL as the initial minimum 11 | 12 | L1: ; Start of the loop to find the minimum 13 | inc si ; Increment SI to point to the next element 14 | cmp al, degrees[si]; Compare the current minimum (AL) with the next element 15 | JL L2 ; Jump to L2 if AL is less than degrees[si] (signed comparison) 16 | mov al, degrees[si]; Update AL with the new minimum if degrees[si] is smaller 17 | L2: ; Label for the jump 18 | Loop L1 ; Decrement CX and loop back to L1 if CX is not zero 19 | 20 | mov min_degree, al ; Store the final minimum value in min_degree 21 | 22 | ; Set up video mode to display the message at a specific location 23 | mov ax, 0B800h ; Load the video segment address (0B800h) into AX 24 | mov es, ax ; Move AX to ES (extra segment) for video memory 25 | mov si, 0 ; Reset SI to 0 to index the MSG array 26 | mov di, 320h ; Set DI to 320h (160 characters * 2 bytes per character) for display position 27 | mov cx, 19 ; Set CX to 19 for the length of the message 'Minimum is detected' 28 | 29 | L3: ; Start of the loop to display the message 30 | mov al, MSG[si] ; Load the next character of MSG into AL 31 | mov es:[di], al ; Store the character at the video memory location (ES:DI) 32 | inc si ; Increment SI to point to the next character 33 | add di, 2 ; Increment DI by 2 (skip attribute byte in video memory) 34 | Loop L3 ; Decrement CX and loop back to L3 if CX is not zero 35 | 36 | ret ; Return from the program 37 | 38 | DEGREES db +25, -20, -10, -30, -13, -25, +22, +30 ; Define the signed byte array with 8 temperature degrees 39 | MIN_DEGREE db ? ; Reserve a byte for the minimum degree variable 40 | MSG db 'Minimum is detected' ; Define the message string (19 characters) -------------------------------------------------------------------------------- /Lab 10/Ex11_CallableFutureExample.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.concurrent.*; 3 | 4 | public class Ex11_CallableFutureExample { 5 | public static void main(String[] args) { 6 | // Create a thread pool with 3 threads 7 | ExecutorService executor = Executors.newFixedThreadPool(3); 8 | 9 | // Create three tasks that return a result 10 | Callable task1 = () -> { 11 | Thread.sleep(1000); // Simulate 1 second work 12 | return "Result from Task 1"; 13 | }; 14 | 15 | Callable task2 = () -> { 16 | Thread.sleep(1500); // Simulate 1.5 seconds work 17 | return "Result from Task 2"; 18 | }; 19 | 20 | Callable task3 = () -> { 21 | Thread.sleep(500); // Simulate 0.5 second work 22 | return "Result from Task 3"; 23 | }; 24 | 25 | // Submit all tasks to executor and get Future objects 26 | Future future1 = executor.submit(task1); 27 | Future future2 = executor.submit(task2); 28 | Future future3 = executor.submit(task3); 29 | 30 | // Retrieve and print results in order 31 | try { 32 | System.out.println(future3.get()); // Should complete first (shortest sleep) 33 | System.out.println(future1.get()); 34 | System.out.println(future2.get()); 35 | } catch (InterruptedException | ExecutionException e) { 36 | e.printStackTrace(); // Handle interruptions or task failures 37 | } finally { 38 | executor.shutdown(); // Always shutdown the executor service 39 | } 40 | } 41 | } 42 | 43 | /* 44 | 45 | Main Points: 46 | ExecutorService with a fixed thread pool (3 threads) is used to run tasks concurrently. 47 | 48 | Callable tasks are created, each returning a String result. 49 | 50 | submit() submits tasks and returns a Future for each, representing their pending results. 51 | 52 | future.get() waits (blocks) until the task finishes and gives the actual result. 53 | 54 | Tasks are retrieved in a specific order, but depending on their work time, some results are available earlier (like future3). 55 | 56 | Always shutdown the executor after tasks finish to release resources. 57 | 58 | */ 59 | 60 | -------------------------------------------------------------------------------- /Lab 11/Ex17_CyclicBarrierExample.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.*; 2 | 3 | /** 4 | * Demonstrates CyclicBarrier usage to synchronize threads at a common point. 5 | */ 6 | public class Ex17_CyclicBarrierExample { 7 | public static void main(String[] args) { 8 | // Create a CyclicBarrier for 3 threads with a barrier action 9 | CyclicBarrier barrier = new CyclicBarrier(3, 10 | // This runs when all threads reach the barrier 11 | () -> System.out.println("All threads reached the barrier, continue together.") 12 | ); 13 | 14 | // Task that threads will execute 15 | Runnable task = () -> { 16 | System.out.println(Thread.currentThread().getName() + " is waiting."); 17 | try { 18 | // Simulate variable work time (0-1000ms) 19 | Thread.sleep((int)(Math.random() * 1000)); 20 | 21 | // Wait here until all 3 threads reach this point 22 | barrier.await(); 23 | 24 | // This executes after all threads pass the barrier 25 | System.out.println(Thread.currentThread().getName() + " passed the barrier."); 26 | } catch (Exception ignored) { 27 | // Handle interruption or barrier broken exceptions 28 | } 29 | }; 30 | 31 | // Start 3 threads (must match barrier's party count) 32 | for (int i = 0; i < 3; i++) { 33 | new Thread(task).start(); 34 | } 35 | } 36 | } 37 | /* 38 | Key Points: 39 | Synchronization Tool: Coordinates threads to wait for each other at a barrier point 40 | Reusable: Unlike CountDownLatch, can be reset after threads are released 41 | Barrier Action: Optional callback that runs when all threads reach the barrier 42 | Thread Count: Number of threads must match the barrier's party count (3 in this case) 43 | Use Cases: Parallel computation phases, multi-threaded testing 44 | 45 | Behavior Flow: 46 | Each thread works independently until calling await() 47 | Threads block at the barrier until all 3 arrive 48 | Barrier action executes (if provided) 49 | All threads are released simultaneously 50 | Threads continue execution after the barrier 51 | 52 | This pattern is useful for synchronizing phases of parallel computation where threads need to wait for peers before proceeding. 53 | */ -------------------------------------------------------------------------------- /Lab 06/Ex_01.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Ex_01.c 3 | * Description: This program demonstrates the basic usage of POSIX threads (pthreads) in C. 4 | * It creates a new thread that prints a message, and the main thread waits 5 | * for the newly created thread to finish before printing its own message. 6 | * The program illustrates thread creation, thread execution, and thread joining. 7 | */ 8 | 9 | #include // Include the pthread library for thread management 10 | #include // Include the standard I/O library for input/output operations 11 | 12 | // Function: thread_function 13 | // Description: This function is executed by the new thread when it starts. 14 | // It prints a message to the console and then exits. 15 | // Parameters: 16 | // - arg: A pointer to the argument passed to the thread (unused in this example). 17 | // Returns: NULL, as the function does not need to return any value. 18 | void* thread_function(void* arg) { 19 | printf("Hello from thread!\n"); // Print a message from the new thread 20 | return NULL; // Return NULL to indicate successful completion 21 | } 22 | 23 | // Function: main 24 | // Description: The main function of the program. It creates a new thread, waits for it 25 | // to finish, and then prints a message from the main thread. 26 | // Returns: 0 to indicate successful program termination. 27 | int main() { 28 | pthread_t thread_id; // Declare a variable to store the thread ID 29 | 30 | // Create a new thread 31 | // Parameters: 32 | // - &thread_id: Pointer to the thread ID variable where the ID of the new thread will be stored. 33 | // - NULL: Use default thread attributes. 34 | // - thread_function: The function that the new thread will execute. 35 | // - NULL: No argument is passed to the thread function. 36 | pthread_create(&thread_id, NULL, thread_function, NULL); 37 | 38 | // Wait for the newly created thread to finish execution 39 | // Parameters: 40 | // - thread_id: The ID of the thread to wait for. 41 | // - NULL: No return value is expected from the thread. 42 | pthread_join(thread_id, NULL); 43 | 44 | // Print a message from the main thread after the new thread has finished 45 | printf("Main thread finished.\n"); 46 | 47 | return 0; // Return 0 to indicate successful program termination 48 | } -------------------------------------------------------------------------------- /Lab 11/Ex12_MultiThreadPriorityDemo.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * This class demonstrates thread priorities in Java with 5 threads. 4 | * Each thread has a different priority level, showing how the JVM 5 | * may (but doesn't always) prioritize higher-priority threads. 6 | */ 7 | public class Ex12_MultiThreadPriorityDemo { 8 | public static void main(String[] args) { 9 | // Create 5 threads with different priorities 10 | Thread t1 = new Thread(() -> { 11 | for (int i = 0; i < 5; i++) { 12 | System.out.println("Thread 1 - MIN_PRIORITY (1)"); 13 | } 14 | }); 15 | 16 | Thread t2 = new Thread(() -> { 17 | for (int i = 0; i < 5; i++) { 18 | System.out.println("Thread 2 - Priority 3"); 19 | } 20 | }); 21 | 22 | Thread t3 = new Thread(() -> { 23 | for (int i = 0; i < 5; i++) { 24 | System.out.println("Thread 3 - NORM_PRIORITY (5)"); 25 | } 26 | }); 27 | 28 | Thread t4 = new Thread(() -> { 29 | for (int i = 0; i < 5; i++) { 30 | System.out.println("Thread 4 - Priority 7"); 31 | } 32 | }); 33 | 34 | Thread t5 = new Thread(() -> { 35 | for (int i = 0; i < 5; i++) { 36 | System.out.println("Thread 5 - MAX_PRIORITY (10)"); 37 | } 38 | }); 39 | 40 | // Set different priorities (1 to 10) 41 | t1.setPriority(Thread.MIN_PRIORITY); // Priority 1 (lowest) 42 | t2.setPriority(3); // Custom priority 3 43 | t3.setPriority(Thread.NORM_PRIORITY); // Priority 5 (default) 44 | t4.setPriority(7); // Custom priority 7 45 | t5.setPriority(Thread.MAX_PRIORITY); // Priority 10 (highest) 46 | 47 | // Start all threads 48 | t1.start(); 49 | t2.start(); 50 | t3.start(); 51 | t4.start(); 52 | t5.start(); 53 | } 54 | } 55 | /* 56 | Expected Behavior: 57 | - Higher-priority threads (e.g., t5) are more likely to execute first, but not guaranteed. 58 | - The JVM and OS scheduler ultimately decide the execution order. 59 | Note: While higher priority threads are more likely to be scheduled first, this behavior 60 | isn't guaranteed as it depends on the JVM implementation and OS scheduling. 61 | */ -------------------------------------------------------------------------------- /Lab 11/Ex13_WaitNotifyExample.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * SharedData class demonstrates basic wait-notify mechanism for thread coordination. 4 | * One thread produces data while another consumes it, with proper synchronization. 5 | */ 6 | class SharedData { 7 | private boolean ready = false; // Shared flag to indicate data readiness 8 | 9 | // Producer method - marks data as ready and notifies waiting thread 10 | synchronized void produce() { 11 | ready = true; 12 | System.out.println("Produced."); 13 | notify(); // Wake up any thread waiting on this object's monitor 14 | } 15 | 16 | // Consumer method - waits until data is ready before consuming 17 | synchronized void consume() { 18 | while (!ready) { // Always use wait() in a loop to guard against spurious wakeups 19 | try { 20 | wait(); // Releases lock and waits for notification 21 | } catch (InterruptedException e) { 22 | // Handle interruption if needed 23 | } 24 | } 25 | System.out.println("Consumed."); 26 | } 27 | } 28 | 29 | /** 30 | * Demonstration of producer-consumer pattern using wait() and notify(). 31 | */ 32 | public class Ex13_WaitNotifyExample { 33 | public static void main(String[] args) { 34 | SharedData data = new SharedData(); 35 | 36 | // Start consumer thread first (it will wait) 37 | new Thread(() -> data.consume()).start(); 38 | 39 | // Start producer thread (it will notify) 40 | new Thread(() -> data.produce()).start(); 41 | } 42 | } 43 | /* 44 | Main Points: 45 | Synchronized Methods: Both produce() and consume() are synchronized to ensure thread-safe access to the shared ready flag 46 | 47 | Wait-Notify Mechanism: 48 | 49 | wait() releases the lock and puts the thread in waiting state 50 | 51 | notify() wakes up one waiting thread 52 | 53 | Spurious Wakeups Protection: The while (!ready) loop guards against accidental wakeups 54 | 55 | Thread Coordination: Demonstrates basic producer-consumer pattern where: 56 | 57 | Consumer waits for data to be ready 58 | 59 | Producer marks data ready and notifies the consumer 60 | 61 | Order Independence: Works correctly regardless of which thread starts first 62 | 63 | Object Monitor: Uses the intrinsic lock of the SharedData object for synchronization 64 | 65 | */ -------------------------------------------------------------------------------- /Lab 4 - Exercises.md: -------------------------------------------------------------------------------- 1 | ## Lab 4 - Exercises - Assembly - Emu8086 2 | 3 | ### Table of Contents 4 | 5 | 1. [Ex_28](#ex_28) 6 | 2. [Ex_29](#ex_29) 7 | 3. [Ex_30](#ex_30) 8 | 4. [Ex_31](#ex_31) 9 | 5. [Ex_32](#ex_32) 10 | 6. [Ex_33](#ex_33) 11 | 12 | --- 13 | 14 | ### **Ex_28** 15 | 16 | Write a program in Assembly language that **saves** the 16-single hexadecimal elements of array **DATA = 00h, 01h, 02h, 03h, 04h, 05h, 06h, 07h, 08h, 09h, 0Ah, 0Bh, 0Ch, 0Dh, 0Eh, 0Fh** using **LOOP**. Calculate the **sum** and the **average** of the **DATA** elements and **save** them in variables named **SUM** and **AVG** respectively. 17 | 18 | --- 19 | 20 | ### **Ex_29** 21 | 22 | Write a program in Assembly language that **copies** array of string named **SOURCE**, which has the following **41-characters** '**Assembly language is a low level language**', into another array named **TARGET**. 23 | 24 | --- 25 | 26 | ### **Ex_30** 27 | 28 | Write a program in Assembly language that **fills** two arrays with the first one hundred unsigned decimal numbers. The first array named **EDATA**, has the first **50-unsigned** even decimal numbers **(0, 2, 4, ..., 96, 98)**. The second array named **ODATA**, has the first **50-unsigned** odd decimal numbers **(1, 3, 5, ..., 97, 99)**. 29 | Calculate the **sum** and the **average** for each array element and **save** them in variables named **SUME**, **SUMO**, **AVGEQ**, **AVGER**, **AVGOQ**, and **AVGOR**. Finally, **exchange** the **EDATA** and **ODATA** array elements. 30 | 31 | --- 32 | 33 | ### **Ex_31** 34 | 35 | Write a program in Assembly language that **fills** two consecutive blocks of data using **Loops**. The size of each block is one Kbyte. The first block starts at address **0800h:0200h**. Each memory location of **block1** is filled with **7Eh** while each memory location of **block2** is filled with **E7h**. Finally, **Exchange** the data of the two blocks. 36 | 37 | --- 38 | 39 | ### **Ex_32** 40 | 41 | Write a program in an assembly language that **compares** between two unsigned variables. **VAR1 = 7Fh** and **VAR2 = 80h**. Then **save** the highest and lowest variables in **HIGH** and **LOW** variables respectively. 42 | 43 | --- 44 | 45 | ### **Ex_33** 46 | 47 | Write a program in an assembly language that **compares** between two signed variables. **VAR1 = 7Fh** and **VAR2 = 80h**. Then **save** the highest and lowest variables in **HIGH** and **LOW** variables respectively. 48 | 49 | --- 50 | -------------------------------------------------------------------------------- /Lab 2 - Exercises.md: -------------------------------------------------------------------------------- 1 | ## Lab 2 - Exercises - Assembly - Emu8086 2 | 3 | ### Table of Contents 4 | - [Ex_07](#ex_07) 5 | - [Ex_08](#ex_08) 6 | - [Ex_09](#ex_09) 7 | - [Ex_10](#ex_10) 8 | - [Ex_11](#ex_11) 9 | 10 | ### **Ex_07** 11 | Using emu8086 program, write a program in Assembly language that **performs** the following tasks, showing the contents of the affected **registers** and flags: 12 | 13 | A) **Initialize** the **AX**, **BX**, and **DI** **registers** with the immediate values 1020H, 3040H, and 0200H respectively. 14 | 15 | B) One's complement the low byte of **AX** **register**. 16 | 17 | C) Two's complement the high byte of the **BX** **register**. 18 | 19 | D) **Save** the high byte of **AX** and the low byte of **BX** at the data segment memory locations addressed by **DI** respectively. 20 | 21 | ### **Ex_08** 22 | Write a program that **performs** the following: 23 | 24 | A) **Initialize** the **AX** and **BX** **registers** by 100h and 200h respectively. 25 | 26 | B) **Add** 50h to the contents of **AX** **register** then increase the result by one. **Subtract** 50h from the contents of **BX** **register** then decrease the result by one. Finally, **swap** the data in the previous **registers**. 27 | 28 | C) **Save** a data of 300h and 400h into the data segment memory locations addressed by 600h and its consecutive addresses respectively. **Add** the contents of the previous memory locations and **save** the result into the **CX** **register**. 29 | 30 | D) Run the program and show the affected **registers**, flags and memory locations. 31 | 32 | ### **Ex_09** 33 | Write a program to **perform** the following tasks, showing the contents of **registers**, memory locations and the affected flags: 34 | 35 | A) **Initialize** the **AX** **register** by FF00h, **set** the rightmost 8 bits of **AX**, **clear** bits 8 and 9 of **AX** and **invert** the leftmost 6 bits of **AX** with the result stored in **BX** **register**. 36 | 37 | B) **Initialize** the low order byte of the **CX** **register** by EFh as well as **save** its one's complement at the high order byte of the **CX** **register**. 38 | 39 | C) **Initialize** the low order byte of the **DX** **register** by EFh as well as **save** its 2's complement at the high order byte of the **DX** **register**. 40 | 41 | ### **Ex_10** 42 | Write an assembly program that calculates a rectangle area, which has 7h and 3h dimensions. Also, calculates the half of the rectangle area. **Save** the results into area and half_area variables. 43 | 44 | ### **Ex_11** 45 | Write a program that calculates the factorial of 5 (5!). **Save** the result into factorial5 variable. -------------------------------------------------------------------------------- /Lab 10/Lambda Expersion.md: -------------------------------------------------------------------------------- 1 | ### **Lambda Expression in Java - Simple Explanation** 2 | 3 | A **lambda expression** is a **shortcut** to write a small piece of code that can be passed around like a variable. It’s mainly used to implement **functional interfaces** (interfaces with a **single abstract method**, like `Runnable`, `Callable`, or `Comparator`). 4 | 5 | --- 6 | 7 | ### **🔹 Traditional Way (Without Lambda)** 8 | ```java 9 | Runnable r = new Runnable() { 10 | @Override 11 | public void run() { 12 | System.out.println("Hello from Runnable!"); 13 | } 14 | }; 15 | new Thread(r).start(); 16 | ``` 17 | 18 | ### **🔹 With Lambda (Shorter & Cleaner)** 19 | ```java 20 | Runnable r = () -> System.out.println("Hello from Lambda!"); 21 | new Thread(r).start(); 22 | ``` 23 | **OR even shorter:** 24 | ```java 25 | new Thread(() -> System.out.println("Hello from Lambda!")).start(); 26 | ``` 27 | 28 | --- 29 | 30 | ### **🔹 Lambda Syntax** 31 | ```java 32 | (parameters) -> { body } 33 | ``` 34 | - If **only one parameter**, parentheses `()` are optional. 35 | - If **only one statement**, braces `{}` and `return` are optional. 36 | 37 | | Example | Meaning | 38 | |---------|---------| 39 | | `() -> System.out.println("Hi")` | Takes **no input**, prints "Hi" | 40 | | `(x) -> x * 2` | Takes **x**, returns `x * 2` | 41 | | `(a, b) -> a + b` | Takes **a and b**, returns `a + b` | 42 | | `s -> s.length() > 5` | Takes **s**, checks if length > 5 | 43 | 44 | --- 45 | 46 | ### **🔹 Where Are Lambdas Used?** 47 | 1. **With `Runnable` (Threads)** 48 | ```java 49 | new Thread(() -> System.out.println("Running in a thread!")).start(); 50 | ``` 51 | 52 | 2. **With `Comparator` (Sorting)** 53 | ```java 54 | List names = Arrays.asList("Alice", "Bob", "Charlie"); 55 | names.sort((a, b) -> a.length() - b.length()); 56 | ``` 57 | 58 | 3. **With `forEach` (Collections)** 59 | ```java 60 | List numbers = List.of(1, 2, 3); 61 | numbers.forEach(num -> System.out.println(num * 2)); 62 | ``` 63 | 64 | --- 65 | 66 | ### **🔹 Why Use Lambdas?** 67 | ✅ **Shorter code** – No need for anonymous classes. 68 | ✅ **Readable** – Focuses on **what** the code does, not boilerplate. 69 | ✅ **Functional programming** – Enables passing behavior as data. 70 | 71 | --- 72 | 73 | ### **🔹 Real-World Analogy** 74 | Imagine you want to **order a pizza**: 75 | - **Traditional way** → Write a full letter explaining how to make it. 76 | - **Lambda way** → Just say **"Pepperoni, large"** (short and clear). 77 | 78 | --- 79 | 80 | ### **🔹 Summary** 81 | - **Lambda = Shortcut for single-method interfaces** 82 | - **Syntax:** `(params) -> { body }` 83 | - **Used in threads, sorting, streams, etc.** 84 | 85 | -------------------------------------------------------------------------------- /Lab 5 - Exercises.md: -------------------------------------------------------------------------------- 1 | ## Lab 5 - Exercises - Assembly - Emu8086 2 | 3 | ### Table of Contents 4 | 5 | 1. [Ex_34](#ex_34) 6 | 2. [Ex_35](#ex_35) 7 | 3. [Ex_36](#ex_36) 8 | 4. [Ex_37](#ex_37) 9 | 5. [Ex_38](#ex_38) 10 | 6. [Ex_39](#ex_39) 11 | 7. [Ex_40](#ex_40) 12 | 13 | *** 14 | 15 | ### **Ex_34** 16 | 17 | Write a program in Assembly language that **saves** the characters of the string ‘**HELLO**’ in array named **MESSAGE** and print them using PUTC. Print the string ‘**DISPLAYING IS DONE**’ at the screen center (row = 12, column = 40). 18 | 19 | *** 20 | 21 | ### **Ex_35** 22 | 23 | Write a program in Assembly language that **displays** the characters of the string ‘**HELLO**’ that starts after 40 characters from the beginning of DS segment using video mode. 24 | (Note: the beginning of video mode is B800h i.e. DS = B800h) 25 | 26 | *** 27 | 28 | ### **Ex_36** 29 | 30 | Write a program in Assembly language that **displays** the characters of the string ‘**HELLO**’ at row = 0 and column = 40 using display mode and ES segment. 31 | (Note: **ES = B800h**) 32 | 33 | *** 34 | 35 | ### **Ex_37** 36 | 37 | Using emu8086 program, write a program in Assembly language that **add** two signed byte elements of byte-array **VAR = 80h, 0FFh** and **save** the result in variable named **SUM** then **display** the string '**All done**'. 38 | 39 | *** 40 | 41 | ### **Ex_38** 42 | 43 | Using emu8086 program, write a program in Assembly language that **adds** the all elements of the unsigned byte array named DATA, which has eight elements: **7Fh, 0B2h, 35h, 0FEh, 0C9h, 80h, 9Eh** and **11h**. **Save** the result in variable **SUM**. Also, **calculate** the average and **save** it in variables **AVGQ** and **AVGR**. **Display** '**summation is done**' after **80** characters from the beginning of **ES segment**, using video mode. 44 | (Note: **DS = 0B800H in video mode**). 45 | 46 | *** 47 | 48 | ### **Ex_39** 49 | 50 | Using emu8086 program, write a program in Assembly language that **detects** the maximum student grade of the unsigned byte array **GRADES** which has ten student grades: **69, 87, 96, 45, 13, 55, 100, 73, 37** and **66**. **Save** the maximum grade in a variable **MAX_GRADE** then '**Maximum is detected**'. 51 | 52 | *** 53 | 54 | ### **Ex_40** 55 | 56 | Using emu8086 program, write a program in Assembly language that **detects** the lowest temperature degree of the signed byte array **DEGREES**, which has eight temperature degrees: **+25, -20, -10, -30, -13, -25, +22** and **+30**. **Save** the minimum degree in a variable **MIN_DEGREE**. Finally, display '**Minimum is detected**' after **160** characters from the beginning of **ES segmen**t using video mode. 57 | (Note: **ES = 0B800h in video mode**) 58 | 59 | *** 60 | -------------------------------------------------------------------------------- /Info/Comparison.md: -------------------------------------------------------------------------------- 1 | 2 | ## Comparison of the unsigned and signed numbers: 3 | *** 4 | 5 | - **CMP instruction** changes the flag bits **CF, AF, SF, PF, ZF, and OF** according to the comparison result. 6 | 7 | **Comparison of the unsigned numbers:** 8 | 9 | CF and ZF are used to indicate the comparison result of the unsigned operands. 10 | 11 | | Comparison results | Flags | 12 | |--------------------------|---------------------| 13 | | Destination > source | CF=0 and ZF=0 | 14 | | Destination < source | CF=1 | 15 | | Destination = source | ZF=1 | 16 | 17 | *** 18 | 19 | **Comparison of the signed numbers:** 20 | SF, OF, and ZF are used to indicate the comparison result of the signed operands. 21 | 22 | | Comparison results | Flags | 23 | |--------------------------|---------------------| 24 | | Destination > source | SF=OF and ZF=0 | 25 | | Destination < source | SF ≠ OF | 26 | | Destination = source | ZF=1 | 27 | 28 | *** 29 | 30 | **Example:** 31 | MOV AX, 40 32 | CMP AX, 30 ; Result = 10, SF = 0, OF = 0, ZF = 0 33 | 34 | **Example:** 35 | MOV AX, 10 36 | CMP AX, 15 ; Result = -5, SF = 1, OF = 0 37 | 38 | **Example:** 39 | MOV AX, 5 40 | CMP AX, 5 ; Result = 0, ZF = 1 41 | 42 | *** 43 | 44 | **Example:** 45 | MOV AX, 25 46 | CMP AX, 0 ; Result = 25, ZF = 0, CF = 0 47 | 48 | **Example:** 49 | MOV AX, 10 50 | CMP AX, 15 ; Result = -5, CF = 1 51 | 52 | **Example:** 53 | MOV AX, 5 54 | CMP AX, 5 ; Result = 0, ZF = 1 55 | 56 | *** 57 | 58 | **Example:** For each of the following Assembly instructions, show the results of the Compare instructions, SF, ZF, CF, and OF flags. 59 | 60 | MOV AL, 12 ; 12 and 10 are unsigned numbers (12 > 10) 61 | CMP AL, 10 ; result = 2, CF = 0, ZF = 0 62 | 63 | MOV AL, 0 ; 0 and 2 are unsigned numbers (0 < 2) 64 | CMP AL, 2 ; result = -2, CF = 1 65 | 66 | *** 67 | 68 | **Example:** For each of the following signed arithmetic instructions, show the values of the destination operand, SF, ZF, and OF flags. 69 | 70 | ``` 71 | MOV AL, 127 ; AL = +127 = 7Fh 72 | ADD AL, 1 ; AL = -128 = 80h, SF = 1, ZF = 0, OF = 1 73 | 74 | MOV AL, 80h ; AL = 80h = -128 75 | ADD AL, 0FEh ; AL = 7Eh = +126, SF = 0, ZF = 0, OF = 1 76 | 77 | MOV AL, 03h ; AL = 03h = +3 78 | SUB AL, 04h ; AL = -1 = FFh, SF = 1, ZF = 0, OF = 0, SF ≠ OF (destination < source) 79 | 80 | MOV AL, 03h ; AL = +3 81 | SUB AL, 01h ; AL = +2 = 02h, SF = 0, ZF = 0, OF = 0, SF = OF (destination > source) 82 | 83 | MOV AL, 5 ; AL = +5 = 05h 84 | SUB AL, 5 ; AL = +0 = 00h, SF = 0, ZF = 1, OF = 0 (destination = source) 85 | 86 | ``` 87 | 88 | *** -------------------------------------------------------------------------------- /Lab 11/Ex20_AtomicExample.java: -------------------------------------------------------------------------------- 1 | // Import the AtomicInteger class from java.util.concurrent.atomic package 2 | // This provides atomic operations on integers for thread-safe programming 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | public class Ex20_AtomicExample { 6 | // Create an AtomicInteger counter initialized to 0 7 | // AtomicInteger provides thread-safe operations without explicit synchronization 8 | static AtomicInteger counter = new AtomicInteger(0); 9 | 10 | public static void main(String[] args) throws InterruptedException { 11 | // Define a Runnable task that will be executed by multiple threads 12 | // This task increments the counter 1000 times 13 | Runnable increment = () -> { 14 | // Loop 1000 times to increment the counter 15 | for (int i = 0; i < 1000; i++) { 16 | // Atomically increment the counter by 1 17 | // This operation is thread-safe and prevents race conditions 18 | counter.incrementAndGet(); 19 | } 20 | }; 21 | 22 | // Create two threads that will execute the increment task 23 | Thread t1 = new Thread(increment); 24 | Thread t2 = new Thread(increment); 25 | 26 | // Start both threads 27 | t1.start(); 28 | t2.start(); 29 | 30 | // Wait for both threads to complete their execution 31 | // join() makes the main thread wait until t1 and t2 finish 32 | t1.join(); 33 | t2.join(); 34 | 35 | // Print the final value of the counter 36 | // Since we used AtomicInteger, the result should be exactly 2000 37 | // (1000 increments from each thread) with no race conditions 38 | System.out.println("Counter: " + counter.get()); 39 | } 40 | } 41 | /** 42 | * Key Points Explained: 43 | * 44 | * AtomicInteger: 45 | * - A thread-safe integer class that provides atomic operations 46 | * - Ensures that operations like increment are performed atomically without race conditions 47 | * 48 | * incrementAndGet(): 49 | * - Atomically increments the current value by 1 50 | * - Equivalent to ++counter but thread-safe 51 | * 52 | * Thread Management: 53 | * - Two threads are created to execute the same increment task 54 | * - start() begins thread execution 55 | * - join() makes the main thread wait for completion 56 | * 57 | * Thread Safety: 58 | * - Without AtomicInteger, this could result in lost updates due to race conditions 59 | * - With AtomicInteger, the final count will always be 2000 (assuming no exceptions) 60 | * 61 | * Expected Output: 62 | * - The program will consistently print "Counter: 2000" because the atomic operations 63 | * prevent race conditions between threads 64 | */ -------------------------------------------------------------------------------- /Lab 10/ArraySum.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.*; 2 | 3 | public class ArraySum { 4 | 5 | public static void main(String[] args) throws InterruptedException, ExecutionException { 6 | // Create and initialize an array with 1000 elements 7 | int[] array = new int[1000]; 8 | // Initialize array with values 1 to 1000 9 | for (int i = 0; i < array.length; i++) { 10 | array[i] = i + 1; 11 | } 12 | 13 | // Set the number of threads to use for parallel processing 14 | int numThreads = 10; 15 | // Create a thread pool with fixed number of threads 16 | ExecutorService executor = Executors.newFixedThreadPool(numThreads); 17 | // Array to store Future objects that will hold the results from each thread 18 | Future[] results = new Future[numThreads]; 19 | 20 | // Calculate the size of each chunk of the array to be processed by each thread 21 | int chunkSize = array.length / numThreads; 22 | 23 | // Divide the work among threads 24 | for (int i = 0; i < numThreads; i++) { 25 | // Calculate the start index for this thread's chunk 26 | final int start = i * chunkSize; 27 | // Calculate the end index (for last thread, make sure to include remaining elements) 28 | final int end = (i == numThreads - 1) ? array.length : start + chunkSize; 29 | 30 | // Submit a task to the executor for each chunk 31 | results[i] = executor.submit(() -> { 32 | int sum = 0; 33 | // Sum the elements in this thread's assigned chunk 34 | for (int j = start; j < end; j++) { 35 | sum += array[j]; 36 | } 37 | return sum; 38 | }); 39 | } 40 | 41 | // Combine results from all threads 42 | int totalSum = 0; 43 | for (Future result : results) { 44 | // Wait for each thread to complete and get its result 45 | // Note: get() will block until the result is available 46 | totalSum += result.get(); 47 | } 48 | 49 | // Shutdown the executor service to release resources 50 | executor.shutdown(); 51 | // Print the final total sum 52 | System.out.println("Total Sum: " + totalSum); 53 | } 54 | } 55 | /* 56 | Key points explained in the comments: 57 | 1- Array initialization with values 1 to 1000 58 | 2- Thread pool creation with a fixed number of threads 59 | 3- Division of work into chunks for parallel processing 60 | 4- Handling of the last chunk which might be slightly larger if the array size isn't perfectly divisible 61 | 5- The lambda expression that each thread executes to sum its portion 62 | 6- Collection and combination of results from all threads 63 | 7- Proper shutdown of the executor service 64 | 8- Output of the final result 65 | 66 | The code demonstrates a common parallel processing pattern using Java's ExecutorService and 67 | Future interfaces to efficiently sum a large array by dividing the work among multiple threads. 68 | */ -------------------------------------------------------------------------------- /Lab 06/Compile and Run C Files with Threads.md: -------------------------------------------------------------------------------- 1 | To compile and run C files (including those using threads) via the Command Prompt (cmd) in Windows, you'll need a C compiler like **GCC** (from **MinGW** or **MSYS2**) or **Microsoft's MSVC** (via **Visual Studio**). 2 | 3 | Here are the commands for **GCC (MinGW)** since it's commonly used for multi-threaded C programs: 4 | 5 | ### **1. Install GCC (MinGW)** 6 | If you don't have GCC installed: 7 | - Download **MinGW** from [https://sourceforge.net/projects/mingw/](https://sourceforge.net/projects/mingw/) 8 | - Install it and add `gcc` to your **PATH** (e.g., `C:\MinGW\bin`). 9 | 10 | Alternatively, use **MSYS2** (recommended for better package management): 11 | - Download from [https://www.msys2.org/](https://www.msys2.org/) 12 | - Run in MSYS2 terminal: 13 | ```sh 14 | pacman -S mingw-w64-x86_64-gcc 15 | ``` 16 | - Add `C:\msys64\mingw64\bin` to **PATH**. 17 | 18 | --- 19 | 20 | ### **2. Compile a C File (Without Threads)** 21 | ```sh 22 | gcc myfile.c -o myprogram 23 | ``` 24 | - `myfile.c` → Your C source file. 25 | - `-o myprogram` → Output executable name. 26 | 27 | --- 28 | 29 | ### **3. Compile a C File With Threads (POSIX Threads - `pthread`)** 30 | If your program uses `pthread.h` (common for threading in C), link the `pthread` library: 31 | ```sh 32 | gcc myfile.c -o myprogram -pthread 33 | ``` 34 | - `-pthread` ensures proper thread linking. 35 | 36 | --- 37 | 38 | ### **4. Run the Compiled Program** 39 | ```sh 40 | myprogram 41 | ``` 42 | or 43 | ```sh 44 | .\myprogram.exe 45 | ``` 46 | 47 | --- 48 | 49 | ### **Example: Full Process for a Threaded Program** 50 | Suppose you have `thread_example.c`: 51 | ```c 52 | #include 53 | #include 54 | 55 | void* thread_func(void* arg) { 56 | printf("Thread running!\n"); 57 | return NULL; 58 | } 59 | 60 | int main() { 61 | pthread_t thread; 62 | pthread_create(&thread, NULL, thread_func, NULL); 63 | pthread_join(thread, NULL); 64 | printf("Main thread done.\n"); 65 | return 0; 66 | } 67 | ``` 68 | 69 | #### **Compile & Run:** 70 | ```sh 71 | gcc thread_example.c -o thread_example -pthread 72 | .\thread_example.exe 73 | ``` 74 | 75 | --- 76 | 77 | ### **Alternative: Using Microsoft's MSVC (Visual Studio)** 78 | If you have **Visual Studio** installed, you can use **MSVC**: 79 | 1. Open **Developer Command Prompt for VS** (search in Start menu). 80 | 2. Compile: 81 | ```sh 82 | cl myfile.c 83 | ``` 84 | 3. Run: 85 | ```sh 86 | myfile.exe 87 | ``` 88 | - For threads, MSVC uses `` and `CreateThread()` instead of `pthread.h`. 89 | 90 | --- 91 | 92 | ### **Summary** 93 | | Task | Command | 94 | |------|---------| 95 | | **Compile normally** | `gcc file.c -o output` | 96 | | **Compile with threads** | `gcc file.c -o output -pthread` | 97 | | **Run** | `.\output.exe` | 98 | 99 | --- 100 | -------------------------------------------------------------------------------- /Lab 04/Ex_30.asm: -------------------------------------------------------------------------------- 1 | 2 | ; File Name: Ex_30.asm 3 | ; Date: 03-March-2025 4 | ; Author: Mahmoud Esmat 5 | 6 | org 100h ; Set the origin for a DOS .COM program (starts at offset 100h) 7 | 8 | ; Initialize pointers to the arrays 9 | lea si, Edata ; Load address of EDATA into SI (for even numbers) 10 | lea di, Odata ; Load address of ODATA into DI (for odd numbers) 11 | 12 | mov cx, 50 ; Set loop counter to 50 (for 50 even and 50 odd numbers) 13 | mov bl, 00h ; Initialize BL with 0 (starting even number) 14 | mov bh, 01h ; Initialize BH with 1 (starting odd number) 15 | mov ax, 0000h ; AX will store the sum of even numbers 16 | mov dx, 0000h ; DX will store the sum of odd numbers 17 | 18 | OddEven: 19 | mov [si], bl ; Store even number in EDATA 20 | mov [di], bh ; Store odd number in ODATA 21 | 22 | add bl, 2 ; Increment even number by 2 23 | add bh, 2 ; Increment odd number by 2 24 | 25 | add ax, [si] ; Add even number to AX (sum of even numbers) 26 | add dx, [di] ; Add odd number to DX (sum of odd numbers) 27 | 28 | add si, 2 ; Move to the next word in EDATA 29 | add di, 2 ; Move to the next word in ODATA 30 | 31 | loop OddEven ; Repeat for 50 numbers 32 | 33 | mov sume, ax ; Store sum of even numbers in SUME 34 | mov sumo, dx ; Store sum of odd numbers in SUMO 35 | 36 | mov bl, 50 ; Load 50 into BL for division 37 | 38 | div bl ; Divide AX by 50 to calculate average of even numbers 39 | mov avgeq, al ; Store quotient (integer part) in AVGEQ 40 | mov avger, ah ; Store remainder in AVGER 41 | 42 | mov ax, sumo ; Load sum of odd numbers into AX 43 | div bl ; Divide AX by 50 to calculate average of odd numbers 44 | mov avgoq, al ; Store quotient (integer part) in AVGOQ 45 | mov avgor, ah ; Store remainder in AVGOR 46 | 47 | ; Exchange elements of EDATA and ODATA 48 | mov cx, 50 ; Set loop counter to 50 49 | mov si, 0 ; Reset SI index to 0 50 | 51 | Exchange: 52 | mov ax, edata[si] ; Load value from EDATA 53 | xchg ax, odata[si] ; Exchange it with value in ODATA 54 | mov edata[si], ax ; Store exchanged value back in EDATA 55 | 56 | add si, 2 ; Move to the next word 57 | loop Exchange ; Repeat for 50 numbers 58 | 59 | ret ; Return control to OS 60 | 61 | ; Data section 62 | Edata dw 50 dup(?) ; Reserve space for 50 even numbers 63 | Odata dw 50 dup(?) ; Reserve space for 50 odd numbers 64 | sume dw ? ; Variable to store sum of even numbers 65 | sumo dw ? ; Variable to store sum of odd numbers 66 | avgeq db ? ; Quotient of even numbers average 67 | avgoq db ? ; Quotient of odd numbers average 68 | avger db ? ; Remainder of even numbers average 69 | avgor db ? ; Remainder of odd numbers average 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Lab 08/ReadersWriters.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | This program provides a possible solution for the first readers-writers problem using 7 | a mutex and a semaphore. The program uses 10 readers and 5 writers to demonstrate the 8 | solution. You can adjust these values as needed. 9 | */ 10 | 11 | // Semaphore to control access to the shared resource 12 | sem_t wrt; 13 | // Mutex to protect the numreader variable 14 | pthread_mutex_t mutex; 15 | // Shared resource 16 | int cnt = 1; 17 | // Count of active readers 18 | int numreader = 0; 19 | 20 | // Writer function 21 | void *writer(void *wno) 22 | { 23 | // Wait for the semaphore, blocking access for readers 24 | sem_wait(&wrt); 25 | // Modify the shared resource 26 | cnt = cnt * 2; 27 | printf("Writer %d modified cnt to %d\n", (*((int *)wno)), cnt); 28 | // Signal the semaphore, allowing readers to access the resource 29 | sem_post(&wrt); 30 | } 31 | 32 | // Reader function 33 | void *reader(void *rno) 34 | { 35 | // Reader acquires the mutex lock before modifying numreader 36 | pthread_mutex_lock(&mutex); 37 | numreader++; 38 | if (numreader == 1) 39 | { 40 | // If this is the first reader, block the writer 41 | sem_wait(&wrt); 42 | } 43 | pthread_mutex_unlock(&mutex); 44 | 45 | // Reading Section 46 | printf("Reader %d: read cnt as %d\n", *((int *)rno), cnt); 47 | 48 | // After Reading is Done: Now a reader wants to leave 49 | // Reader acquires the mutex lock before modifying numreader 50 | pthread_mutex_lock(&mutex); 51 | numreader--; 52 | if (numreader == 0) 53 | { 54 | // If this is the last reader, wake up the writer 55 | sem_post(&wrt); 56 | } 57 | pthread_mutex_unlock(&mutex); 58 | } 59 | 60 | int main() 61 | { 62 | // Arrays to hold reader and writer thread identifiers 63 | pthread_t read[10], write[5]; 64 | 65 | // Initialize the mutex and semaphore 66 | pthread_mutex_init(&mutex, NULL); 67 | sem_init(&wrt, 0, 1); 68 | 69 | // Array used for numbering the readers and writers 70 | int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 71 | 72 | // Create reader threads 73 | for (int i = 0; i < 10; i++) 74 | { 75 | pthread_create(&read[i], NULL, (void *)reader, (void *)&a[i]); 76 | } 77 | // Create writer threads 78 | for (int i = 0; i < 5; i++) 79 | { 80 | pthread_create(&write[i], NULL, (void *)writer, (void *)&a[i]); 81 | } 82 | 83 | // Wait for all reader threads to finish 84 | for (int i = 0; i < 10; i++) 85 | { 86 | pthread_join(read[i], NULL); 87 | } 88 | // Wait for all writer threads to finish 89 | for (int i = 0; i < 5; i++) 90 | { 91 | pthread_join(write[i], NULL); 92 | } 93 | 94 | // Destroy the mutex and semaphore 95 | pthread_mutex_destroy(&mutex); 96 | sem_destroy(&wrt); 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /Lab 07/pthread_join.md: -------------------------------------------------------------------------------- 1 | ### **Explanation of `pthread_join(id, (void **)&ptr)`** 2 | 3 | This line is used to **wait for a thread to finish execution** and **retrieve its return value**. Here's a breakdown: 4 | 5 | --- 6 | 7 | ### **1. Purpose of `pthread_join`** 8 | - **Blocks the calling thread** (usually the `main` thread) until the specified thread (`id`) completes. 9 | - **Retrieves the exit status** (return value) of the joined thread. 10 | - Helps in **synchronizing threads** (prevents the program from exiting before the thread finishes). 11 | 12 | --- 13 | 14 | ### **2. Syntax** 15 | ```c 16 | int pthread_join(pthread_t thread, void **retval); 17 | ``` 18 | - **`thread`** → The thread ID (`id` in this case) to wait for. 19 | - **`retval`** → A pointer to a location where the thread’s return value will be stored. 20 | 21 | --- 22 | 23 | ### **3. Breaking Down `(void **)&ptr`** 24 | - **`ptr`** is an `int*` (pointer to an integer). 25 | - **`&ptr`** gives the **address of the pointer** (`int**` type). 26 | - **`(void **)`** is a typecast to match `pthread_join`'s expected argument type (`void**`). 27 | 28 | #### **Why `(void **)`?** 29 | - `pthread_join` expects a generic pointer (`void**`) to store the thread’s return value. 30 | - The thread function (`foo`) returns `void*` (a generic pointer), so we need to cast `&ptr` to `void**` to receive it correctly. 31 | 32 | --- 33 | 34 | ### **4. What Happens in This Code?** 35 | 1. **Thread `foo` returns `&i`** (address of the global variable `i`). 36 | - `pthread_exit(&i)` is equivalent to returning `(void*) &i`. 37 | 38 | 2. **`pthread_join` captures this address** and stores it in `ptr`. 39 | - After `pthread_join`, `ptr` points to `i` (now modified to `10`). 40 | 41 | 3. **`*ptr` dereferences the pointer**, giving the value `10`. 42 | 43 | --- 44 | 45 | ### **5. Example Flow** 46 | ```c 47 | int *ptr; // Declare a pointer to int 48 | pthread_join(id, (void **)&ptr); // Wait for thread 'id' and store its return value in 'ptr' 49 | printf("%i\n", *ptr); // Prints 10 (value of 'i' returned by foo()) 50 | ``` 51 | 52 | --- 53 | 54 | ### **6. Key Notes** 55 | - **Error Handling**: `pthread_join` returns `0` on success, non-zero on failure. 56 | - **Null Return**: If the thread returns `NULL`, `ptr` will be `NULL`. 57 | - **No Join**: If you don’t join a thread, its resources might leak (like memory or OS thread handles). 58 | 59 | --- 60 | 61 | ### **7. Why Not Just Use `void* ptr`?** 62 | - `pthread_join` needs to **modify the pointer itself** (not just the value it points to), so we pass the **address of the pointer** (`&ptr`). 63 | 64 | --- 65 | 66 | ### **Summary** 67 | | Code | Explanation | 68 | |------|-------------| 69 | | `pthread_join(id, (void **)&ptr)` | Waits for thread `id` to finish and stores its return value (`&i`) in `ptr`. | 70 | | `(void **)&ptr` | Typecasts `int**` to `void**` to match `pthread_join`'s expected argument. | 71 | | `*ptr` | Dereferences the pointer to get the value returned by the thread (`10`). | 72 | 73 | This mechanism ensures **safe communication** between threads. 74 | 75 | --- -------------------------------------------------------------------------------- /Lab 07/Ex_15.c: -------------------------------------------------------------------------------- 1 | // Semaphore: Example 1 2 | 3 | #include // Standard I/O library for printf 4 | #include // POSIX thread library for creating and managing threads 5 | #include // Semaphore library for synchronizing threads 6 | #include // For sleep function 7 | 8 | #define NUM_THREADS 5 // Define the number of threads to create 9 | 10 | int counter = 0; // Shared counter variable to be incremented by threads 11 | sem_t semaphore; // Semaphore to control access to the shared counter 12 | /* 13 | - Semaphore is another synchronization mechanism that can be used to control access 14 | to a resource. Unlike mutexes, semaphores can allow more than one thread to access 15 | a resource concurrently, based on the semaphore's value. 16 | - If the semaphore is initialized with a value of 1, which effectively makes it 17 | a binary semaphore (similar to a mutex). 18 | - Semaphores: The semaphore is used to ensure that only one thread can increment 19 | the counter at a time, providing mutual exclusion for the critical section (counter++). 20 | This prevents race conditions where multiple threads try to update the counter 21 | simultaneously. 22 | */ 23 | // Function executed by each thread 24 | void *increment_counter(void *threadid) 25 | { 26 | long tid = (long)threadid; // Cast the thread ID to a long 27 | printf("Thread %ld starting\n", tid); 28 | 29 | for (int i = 0; i < 1000; i++) // Each thread increments the counter 1000 times 30 | { 31 | sem_wait(&semaphore); // Wait (decrement) the semaphore to enter the critical section 32 | counter++; // Increment the shared counter 33 | sem_post(&semaphore); // Signal (increment) the semaphore to leave the critical section 34 | } 35 | printf("Thread %ld done\n", tid); // Indicate that the thread is done 36 | pthread_exit(NULL); // Exit the thread 37 | } 38 | 39 | int main() 40 | { 41 | pthread_t threads[NUM_THREADS]; // Array to hold thread identifiers 42 | sem_init(&semaphore, 0, 1); // Initialize the semaphore with an initial value of 1 43 | /* 44 | First parameter: - Pointer to the semaphore variable to initialize 45 | Second parameter: - Indicates the sharing scope of the semaphore: 46 | 0: The semaphore is local to the current process (shared only between threads of the same process). 47 | Non-zero (1 or another value): The semaphore is shared between multiple processes (must be placed in shared memory). 48 | Third parameter: - The initial value of the semaphore (here, it starts at 1, making it a binary semaphore for mutual exclusion). 49 | */ 50 | 51 | // Create NUM_THREADS threads 52 | for (long t = 0; t < NUM_THREADS; t++) 53 | { 54 | pthread_create(&threads[t], NULL, increment_counter, (void *)t); 55 | } 56 | 57 | // Wait for all threads to complete 58 | for (int t = 0; t < NUM_THREADS; t++) 59 | { 60 | pthread_join(threads[t], NULL); 61 | } 62 | 63 | printf("Final counter value: %d\n", counter); // Print the final value of the counter 64 | 65 | sem_destroy(&semaphore); // Destroy the semaphore to free resources 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /Lab 3 - Exercises.md: -------------------------------------------------------------------------------- 1 | ## Lab 3 - Exercises - Assembly - Emu8086 2 | 3 | ### Table of Contents 4 | 1. [Ex_12](#ex_12) 5 | 2. [Ex_13](#ex_13) 6 | 3. [Ex_14](#ex_14) 7 | 4. [Ex_15](#ex_15) 8 | 5. [Ex_16](#ex_16) 9 | 6. [Ex_17](#ex_17) 10 | 7. [Ex_18](#ex_18) 11 | 8. [Ex_19](#ex_19) 12 | 9. [Ex_20](#ex_20) 13 | 10. [Ex_21](#ex_21) 14 | 11. [Ex_26](#ex_26) 15 | 12. [Ex_27](#ex_27) 16 | 17 | --- 18 | 19 | **Ex_22 to Ex_25** : Attached with the assembly files. 20 | 21 | --- 22 | 23 | ### **Ex_12** 24 | Write a program that calculates the sum of the first 6 natural numbers and **saves** the result in a variable named **SUM**. 25 | Hint: The formula for sum n natural numbers is **SUM = n (n + 1) / 2**. 26 | 27 | --- 28 | 29 | ### **Ex_13** 30 | In a computer shop, a laptop that sells for an original price 6000 LE is marked a sale rate "20% off". Write a program that calculates the price of the Laptop after sale and **saves** it in a variable named **SPRICE**. 31 | Hint: price after sale = original price - sale & sale = original price x sale rate. 32 | 33 | --- 34 | 35 | ### **Ex_14** 36 | Write a program that **transfers** the elements of the byte array **DATA = 25h, 4Fh, 85h, 1Fh, 2Bh, OC4h** into a byte array **COPY** using index addressing method. 37 | 38 | --- 39 | 40 | ### **Ex_15** 41 | Write a program that: 42 | A) **Saves** the marks (60, 80 and 90), for a student on 3 courses in an array called **Marks**. 43 | B) **Calculates** the summation and the average of student marks and **saves** them in variables named **SUM** and **AVG** respectively. 44 | C) **Transfers** the offset addresses of **SUM** and **AVG** into **SI** and **DI** registers respectively. 45 | 46 | --- 47 | 48 | ### **Ex_16** 49 | Write a program that **calculates** the value of the following expression: 50 | **RESULT = (-VAR1 + VAR2) x VAR3** 51 | Where **VAR1**, **VAR2** and **VAR3** are byte variables, which have the values **15h**, **20h** and **10h** respectively. 52 | 53 | --- 54 | 55 | ### **Ex_17** 56 | Write a program that **copies** the first two elements of the byte array **Marks = 10, 20, 30** into a byte array **COPY** using Indirect Addressing. 57 | 58 | --- 59 | 60 | ### **Ex_18** 61 | Write a program in Assembly language that **transfers** the elements of a byte array **VAR = 10h, 11h, 12h, 13h** into **AL**, **AH**, **BL** and **BH** registers respectively using direct-offset addressing. 62 | 63 | --- 64 | 65 | ### **Ex_19** 66 | Write a program in Assembly language that **transfers** the elements of a word array **VAR = 1010h, 2020h, 3030h** into array **COPY** using direct-offset addressing. 67 | 68 | --- 69 | 70 | ### **Ex_20** 71 | Write a program in Assembly language that **exchanges** the values of **VAR1 = 2000h** and **VAR2 = 3000h** using exchange instruction. 72 | 73 | --- 74 | 75 | ### **Ex_21** 76 | Write a program in Assembly language that **transfers** the initial value of variable **VAR = 1020h** to variable **Copy** indirectly (using indirect addressing). 77 | 78 | --- 79 | 80 | ### **Ex_26** 81 | Write a program in Assembly language that **transfers** the elements of a byte array **DATA = 10h, 11h, 12h, 13h, 14h, 15h** into array **COPY** using **LOOP**. 82 | 83 | --- 84 | 85 | ### **Ex_27** 86 | Write a program in Assembly language that **calculates** and **saves** the sum of the elements of a byte array **DATA = 10h, 10h, 10h, 10h, 10h**. 87 | 88 | --- 89 | -------------------------------------------------------------------------------- /Info/CMP & Flags.md: -------------------------------------------------------------------------------- 1 | ### **How `CMP` Affects CPU Flags in x86 Assembly** 2 | The `CMP` (Compare) instruction is essentially a **subtraction (`SUB`) without storing the result**. It updates the CPU flags based on the difference between two operands. 3 | 4 | #### **Syntax:** 5 | ```assembly 6 | CMP destination, source 7 | ``` 8 | This performs: 9 | ``` 10 | destination - source 11 | ``` 12 | and updates the CPU flags accordingly. 13 | 14 | --- 15 | 16 | ## **Flags Affected by `CMP`** 17 | | **Flag** | **Description** | **How It’s Affected by `CMP`** | 18 | |----------|---------------|--------------------------------| 19 | | **ZF (Zero Flag)** | Set if the result is **zero** (`dest == src`) | `ZF = 1` if `dest == src`, otherwise `ZF = 0` | 20 | | **SF (Sign Flag)** | Set if the result is **negative** (sign bit = 1) | `SF = 1` if result is negative (`MSB = 1`) | 21 | | **OF (Overflow Flag)** | Set if signed overflow occurs | `OF = 1` if result is incorrect due to signed overflow | 22 | | **CF (Carry Flag)** | Set if an unsigned borrow occurs | `CF = 1` if `dest < src` (unsigned borrow happened) | 23 | | **PF (Parity Flag)** | Set if result has an even number of 1-bits | Updated based on result (rarely used) | 24 | 25 | --- 26 | 27 | ## **Effects of `CMP` on Flags - Examples** 28 | ### **1. When `CMP` Sets the Zero Flag (`ZF = 1`)** 29 | ```assembly 30 | mov eax, 5 31 | cmp eax, 5 ; 5 - 5 = 0 → ZF = 1 (equal) 32 | je equal_label ; Jumps because ZF = 1 33 | ``` 34 | 35 | ### **2. When `CMP` Sets the Carry Flag (`CF = 1`) for Unsigned Comparisons** 36 | ```assembly 37 | mov al, 5 38 | cmp al, 10 ; 5 - 10 → CF = 1 (since 5 is smaller in unsigned) 39 | jb below_label ; Jumps because CF = 1 (unsigned comparison) 40 | ``` 41 | 42 | ### **3. When `CMP` Sets the Sign Flag (`SF = 1`) for Signed Comparisons** 43 | ```assembly 44 | mov al, -5 45 | cmp al, 10 ; -5 - 10 = -15 → SF = 1 (negative result) 46 | jl less_label ; Jumps because SF = 1 (signed comparison) 47 | ``` 48 | 49 | ### **4. When `CMP` Sets the Overflow Flag (`OF = 1`) for Signed Overflow** 50 | ```assembly 51 | mov al, 127 ; Largest signed 8-bit value (+127) 52 | cmp al, -128 ; 127 - (-128) → Overflow (out of range) 53 | jo overflow_label ; Jumps if OF = 1 54 | ``` 55 | 56 | --- 57 | 58 | ## **How Flags Are Used in Conditional Jumps** 59 | After `CMP`, conditional jumps determine whether the comparison was signed or unsigned: 60 | 61 | | **Unsigned Jumps** | **Condition (Flags Used)** | 62 | |-------------------|--------------------------| 63 | | `JA` (Jump Above) | `CF = 0, ZF = 0` (`>` unsigned) | 64 | | `JAE` (Jump Above or Equal) | `CF = 0` (`>=` unsigned) | 65 | | `JB` (Jump Below) | `CF = 1` (`<` unsigned) | 66 | | `JBE` (Jump Below or Equal) | `CF = 1 or ZF = 1` (`<=` unsigned) | 67 | 68 | | **Signed Jumps** | **Condition (Flags Used)** | 69 | |-----------------|--------------------------| 70 | | `JG` (Jump Greater) | `ZF = 0, SF = OF` (`>` signed) | 71 | | `JGE` (Jump Greater or Equal) | `SF = OF` (`>=` signed) | 72 | | `JL` (Jump Less) | `SF ≠ OF` (`<` signed) | 73 | | `JLE` (Jump Less or Equal) | `ZF = 1 or SF ≠ OF` (`<=` signed) | 74 | 75 | --- 76 | 77 | ### **Summary** 78 | - `CMP` performs `dest - src` and **does not store the result**, only updates flags. 79 | - **Use `ZF` for equality checks** (`JE`, `JNE`). 80 | - **Use `CF` for unsigned comparisons** (`JA`, `JB`). 81 | - **Use `SF` and `OF` for signed comparisons** (`JG`, `JL`). 82 | - **Signed overflow occurs when a result exceeds the signed number range** (`JO` for detecting it). 83 | -------------------------------------------------------------------------------- /Info/Conditional Jump.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | - [Conditional Jump instructions (J)](#conditional-jump-instructions-j) 8 | - [Jcondition label](#jcondition-label) 9 | - [Conditional Jump instruction for the unsigned numbers:](#conditional-jump-instruction-for-the-unsigned-numbers) 10 | - [Conditional Jump instruction for the signed numbers:](#conditional-jump-instruction-for-the-signed-numbers) 11 | 12 | 13 | 14 | 15 | # Conditional Jump instructions (J) 16 | 17 | - In the 8086 through the 80286 microprocessors, conditional jump instructions are always jump to any location within the current code segment. 18 | 19 | ## Jcondition label 20 | 21 | ; condition : depends on the result from 22 | ; any arithmetic or logic operations (refers to status flags) 23 | ; label : refers to code label 24 | 25 | - If the **condition** under test is **true**, a branch to the **label** associated with the conditional jump instruction is executed. If the **condition** is **false**, the next sequential step in the program is executed. 26 | 27 | *** 28 | 29 | - Although the **CMP** instruction is the same for both unsigned and signed numbers, the **conditional jump instructions** used to make a decision for the **unsigned numbers** are different from the **signed numbers**. 30 | 31 | - **Conditional jump instructions** which are used with **unsigned numbers** are **JA, JB, JAE, JBE, JE, and JNE**. 32 | 33 | - **Conditional jump instructions** which are used with **signed numbers** are **JG, JL, JGE, JLE, JE, and JNE**. 34 | 35 | *** 36 | 37 | ## Conditional Jump instruction for the unsigned numbers: 38 | 39 | | Conditional Jump instruction | Description | Flag condition | 40 | |------------------------------|------------------------------------|----------------------| 41 | | JE, JZ | Jump if equal (zero) | ZF = 1 | 42 | | JNE, JNZ | Jump if not equal (not zero) | ZF = 0 | 43 | | JA, JNBE | Jump if above (not below or equal) | CF=0 and ZF=0 | 44 | | JB, JNAE, JC | Jump if below (not above or equal/carry) | CF=1 | 45 | | JAE, JNB, JNC | Jump if above or equal (not below/not carry) | CF=0 | 46 | | JBE, JNA | Jump if below or equal (not above) | CF=1 or ZF=1 | 47 | | JPE, JP | Jump if parity even | PF=1 | 48 | | JPO, JNP | Jump if parity odd (no parity) | PF=0 | 49 | 50 | *** 51 | 52 | ## Conditional Jump instruction for the signed numbers: 53 | 54 | | Conditional Jump instruction | Description | Flag condition | 55 | |---|---|---| 56 | | JE, JZ | Jump if equal (zero) | ZF = 1 | 57 | | JNE, JNZ | Jump if not equal (not zero) | ZF = 0 | 58 | | JG, JNLE | Jump if greater (not less or equal) | SF=OF and ZF=0 | 59 | | JL, JNGE | Jump if less (not greater or equal) | SF≠OF | 60 | | JGE, JNL | Jump if greater or equal (not less) | SF=OF | 61 | | JLE, JNG | Jump if less or equal (not greater) | SF≠OF or ZF=1 | 62 | | JPE, JP | Jump if parity even | PF=1 | 63 | | JPO, JNP | Jump if parity odd (no parity) | PF=0 | 64 | | JO | Jump if overflow | OF=1 | 65 | | JNO | Jump if not overflow | OF=0 | 66 | | JS | Jump if sign | SF=1 | 67 | | JNS | Jump if not sign | SF=0 | 68 | 69 | *** 70 | -------------------------------------------------------------------------------- /Lab 08/Producer-Consumer2.c: -------------------------------------------------------------------------------- 1 | #include // Standard input and output library 2 | #include // Standard library for memory allocation, process control, etc. 3 | #include // POSIX thread library for creating and managing threads 4 | #include // Semaphore library for synchronization 5 | 6 | #define BUFFER_SIZE 5 // Define the size of the buffer 7 | #define MAX_ITEMS 20 // Define the maximum number of items to be produced and consumed 8 | 9 | int buffer[BUFFER_SIZE]; // Shared buffer array 10 | int in = 0; // Index for the next item to be inserted by the producer 11 | int out = 0; // Index for the next item to be removed by the consumer 12 | int produced_count = 0; // Counter to track the number of items produced 13 | int consumed_count = 0; // Counter to track the number of items consumed 14 | 15 | sem_t mutex; // Semaphore for mutual exclusion (protecting critical sections) 16 | sem_t full; // Semaphore to track the number of full slots in the buffer 17 | sem_t empty; // Semaphore to track the number of empty slots in the buffer 18 | 19 | // Producer thread function 20 | void *producer(void *arg) 21 | { 22 | int item = 1; // Start producing items with the value 1 23 | 24 | // Continue producing items until the maximum count is reached 25 | while (produced_count < MAX_ITEMS) 26 | { 27 | sem_wait(&empty); // Wait if there are no empty slots 28 | sem_wait(&mutex); // Lock the critical section 29 | 30 | // Insert the item into the buffer 31 | buffer[in] = item; 32 | printf("Produced: %d\n", item); // Print the produced item 33 | item++; // Increment the item value for the next production 34 | in = (in + 1) % BUFFER_SIZE; // Update the index circularly 35 | 36 | produced_count++; // Increment the produced count 37 | 38 | sem_post(&mutex); // Unlock the critical section 39 | sem_post(&full); // Signal that a new item is produced (full slot available) 40 | } 41 | 42 | pthread_exit(NULL); // Exit the thread 43 | } 44 | 45 | // Consumer thread function 46 | void *consumer(void *arg) 47 | { 48 | // Continue consuming items until the maximum count is reached 49 | while (consumed_count < MAX_ITEMS) 50 | { 51 | sem_wait(&full); // Wait if there are no full slots 52 | sem_wait(&mutex); // Lock the critical section 53 | 54 | // Remove the item from the buffer 55 | int item = buffer[out]; 56 | printf("Consumed: %d\n", item); // Print the consumed item 57 | out = (out + 1) % BUFFER_SIZE; // Update the index circularly 58 | 59 | consumed_count++; // Increment the consumed count 60 | 61 | sem_post(&mutex); // Unlock the critical section 62 | sem_post(&empty); // Signal that an item has been consumed (empty slot available) 63 | } 64 | 65 | pthread_exit(NULL); // Exit the thread 66 | } 67 | 68 | int main() 69 | { 70 | pthread_t producerThread, consumerThread; // Declare thread variables 71 | 72 | // Initialize semaphores 73 | sem_init(&mutex, 0, 1); // Initialize mutex to 1 (binary semaphore) 74 | sem_init(&full, 0, 0); // Initialize full to 0 (no items produced initially) 75 | sem_init(&empty, 0, BUFFER_SIZE); // Initialize empty to BUFFER_SIZE 76 | 77 | // Create producer and consumer threads 78 | pthread_create(&producerThread, NULL, producer, NULL); 79 | pthread_create(&consumerThread, NULL, consumer, NULL); 80 | 81 | // Wait for the threads to finish 82 | pthread_join(producerThread, NULL); 83 | pthread_join(consumerThread, NULL); 84 | 85 | // Destroy semaphores 86 | sem_destroy(&mutex); 87 | sem_destroy(&full); 88 | sem_destroy(&empty); 89 | 90 | return 0; // Exit the program 91 | } 92 | -------------------------------------------------------------------------------- /Lab 11/Ex15_ReadWriteExample.java: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.locks.*; 2 | 3 | /** 4 | * Demonstration of ReadWriteLock usage to allow concurrent reads 5 | * while maintaining exclusive access for writes. 6 | */ 7 | public class Ex15_ReadWriteExample { 8 | // Create a ReadWriteLock (Reentrant implementation) 9 | private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); 10 | // Shared data that needs protection 11 | private int sharedData = 0; 12 | 13 | /** 14 | * Reads the shared data safely using a read lock. 15 | * Multiple threads can read simultaneously when no writer is active. 16 | */ 17 | public void readData() { 18 | // Acquire the read lock (allows multiple concurrent readers) 19 | rwLock.readLock().lock(); 20 | try { 21 | // Read operation (thread-safe while read lock is held) 22 | System.out.println(Thread.currentThread().getName() + " read: " + sharedData); 23 | } finally { 24 | // Always release the lock in finally block 25 | rwLock.readLock().unlock(); 26 | } 27 | } 28 | 29 | /** 30 | * Writes to the shared data using a write lock. 31 | * Provides exclusive access - blocks all readers and other writers. 32 | * @param value The value to write to shared data 33 | */ 34 | public void writeData(int value) { 35 | // Acquire the write lock (exclusive access) 36 | rwLock.writeLock().lock(); 37 | try { 38 | // Write operation (exclusive while write lock is held) 39 | System.out.println(Thread.currentThread().getName() + " wrote: " + value); 40 | sharedData = value; 41 | } finally { 42 | // Always release the lock in finally block 43 | rwLock.writeLock().unlock(); 44 | } 45 | } 46 | 47 | public static void main(String[] args) { 48 | Ex15_ReadWriteExample obj = new Ex15_ReadWriteExample(); 49 | 50 | // Create and start a writer thread 51 | new Thread(() -> obj.writeData(100), "Writer").start(); 52 | 53 | // Create and start 3 reader threads 54 | for (int i = 0; i < 3; i++) { 55 | // Each reader thread will call readData() 56 | new Thread(obj::readData, "Reader-" + i).start(); 57 | } 58 | } 59 | } 60 | /* 61 | Key Features Explained: 62 | ReadWriteLock Interface: 63 | ReentrantReadWriteLock implementation allows: 64 | Multiple concurrent readers when no writer is active 65 | Exclusive access for a single writer 66 | 67 | Locking Mechanism: 68 | readLock() for shared read access 69 | writeLock() for exclusive write access 70 | 71 | Thread Safety: 72 | All access to sharedData is protected by appropriate locks 73 | finally blocks ensure locks are always released 74 | Concurrency Benefits: 75 | Readers don't block other readers 76 | Writer blocks all readers and other writers 77 | Better performance than full synchronization when reads outnumber writes 78 | Main Method: 79 | Starts 1 writer thread (sets value to 100) 80 | Starts 3 reader threads (read the shared value) 81 | Thread naming helps track execution order in output 82 | 83 | Expected Behavior: 84 | Writer thread gets exclusive access to update the value 85 | Reader threads can read concurrently when no writer is active 86 | 87 | Output will show either: 88 | Writer completes first, then readers see new value 89 | Some readers may see old value if they execute before writer 90 | 91 | Best Practices Illustrated: 92 | Always release locks in finally blocks 93 | Use thread naming for debugging 94 | Separate read and write operations appropriately 95 | Document thread safety guarantees 96 | */ -------------------------------------------------------------------------------- /Lab 1 - Exercises.md: -------------------------------------------------------------------------------- 1 | ## Lab 1 - Exercises - Assembly - Emu8086 2 | 3 | ### Table of Contents 4 | 1. [Ex_01](#ex_1) 5 | 2. [Ex_02](#ex_2) 6 | 3. [Ex_03](#ex_3) 7 | 4. [Ex_04](#ex_4) 8 | 5. [Ex_05](#ex_05) 9 | 6. [Ex_06](#ex_06) 10 | 11 | --- 12 | 13 | ### **Ex_1** 14 | Using emu8086 program, write a program in Assembly language that performs the following tasks, showing the contents of the affected registers, memory locations and flags: 15 | 16 | A) Initialize **AX** and **SI** registers with the immediate value **1520H** and **0300H** respectively. 17 | 18 | B) Save the immediate value **3040H** at the data segment memory location addressed by **SI**. 19 | 20 | C) **Add** the word contents at the data segment memory location addressed by **SI** to **AX** with the sum stored at the **AX** register. 21 | 22 | --- 23 | 24 | ### **Ex_2** 25 | Using emu8086 program, write a program in Assembly language that performs the following tasks, showing the contents of the affected registers and flags: 26 | 27 | A) Initialize **AX** and **DX** registers with the immediate values **1234h** and **5678h** respectively. 28 | 29 | B) **Subtract** the word content of **AX** register from the word content of **DX** register with the difference stored in the **DX** register. 30 | 31 | --- 32 | 33 | ### **Ex_3** 34 | Using emu8086 program, write a program in Assembly language that performs the following tasks, showing the affected registers and memory locations: 35 | 36 | A) Initialize **AL**, **BL**, **CL** and **DL** registers with the immediate data **10h**, **20h**, **30h** and **40h** respectively. 37 | 38 | B) **Copy** the contents of **AL**, **BL**, **CL** and **DL** registers into **BH**, **CH**, **DH** and **AH** registers respectively. 39 | 40 | C) **SWAP** between the contents of **AX** and **BX** registers. 41 | 42 | D) **Copy** the content of **AX** register into the data segment memory location addressed by **0200h** then **copy** the contents of **BX** and **CX** registers at the consecutive offset addresses. 43 | 44 | E) **Copy** the content of **DX** register into the stack segment memory location addressed by **0100h** then **Copy** the immediate data **4433h** and **2211h** at the consecutive offset addresses. 45 | 46 | --- 47 | 48 | ### **Ex_4** 49 | Using emu8086 program, write a program in Assembly language that performs the following tasks, showing the affected registers and memory locations: 50 | 51 | A) **Copy** the string data 'NO' into **AX** register. Initialize the source index register (**SI**) with the initial value **0200H** and the base pointer register (**BP**) with initial value **0100H** then **copy** the contents of **AX** register into the stack segment memory locations addressed by **SI+BP+20H**. 52 | 53 | B) **Initialize** the destination index register (**DI**) with initial value **0300H** then **copy** the string data 'HELLO' into the extra data segment memory locations addressed by **DI+100H**. 54 | 55 | --- 56 | 57 | ### **Ex_05** 58 | Using emu8086 program, write a program in Assembly language that performs the following tasks, showing the affected registers and memory locations: 59 | 60 | A) **Initialize** the **AL** and **SI** registers with **33h** and **0300h** respectively. 61 | 62 | B) **Copy** the data segment memory location addressed by **SI** with **55h**. Then, **swap** between **AL** and the data at the data segment memory. 63 | 64 | --- 65 | 66 | ### **Ex_06** 67 | Using emu8086 program, write a program in Assembly language that performs the following tasks, showing the contents of the affected registers and flags: 68 | 69 | A) **Initialize** the **AL** and **DL** registers with the immediate values **38H** and **0E0H** respectively. 70 | 71 | B) **Set** the rightmost 5-bits of **DL** without changing the remaining bits of **DL**. 72 | 73 | C) **Set** the leftmost 3-bits of **AL**, **clears** bits 2, 3, and 4 of **AL**, and **inverts** the rightmost 2 bits of **AL**. -------------------------------------------------------------------------------- /Lab 07/struct.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Define a struct with different variable types 6 | typedef struct 7 | { 8 | int id; 9 | char name[50]; 10 | float price; 11 | double weight; 12 | bool in_stock; 13 | char category; 14 | } Product; 15 | 16 | // Function prototypes (methods for the struct) 17 | void print_product(Product p); 18 | void increase_price(Product *p, float amount); 19 | void toggle_stock_status(Product *p); 20 | Product create_default_product(); 21 | Product create_custom_product(int id, const char *name, float price, double weight, bool stock, char cat); 22 | 23 | int main() 24 | { 25 | printf("=== Struct Example in C ===\n\n"); 26 | 27 | // Method 1: Initialize struct members one by one 28 | Product p1; 29 | p1.id = 101; 30 | strcpy(p1.name, "Laptop"); 31 | p1.price = 999.99f; 32 | p1.weight = 2.5; 33 | p1.in_stock = true; 34 | p1.category = 'E'; 35 | 36 | printf("Product 1 (initialized individually):\n"); 37 | print_product(p1); 38 | 39 | // Method 2: Initialize at declaration using designated initializers 40 | Product p2 = { 41 | .id = 102, 42 | .name = "Smartphone", 43 | .price = 699.99f, 44 | .weight = 0.3, 45 | .in_stock = false, 46 | .category = 'E'}; 47 | 48 | printf("\nProduct 2 (designated initializers):\n"); 49 | print_product(p2); 50 | 51 | // Method 3: Initialize in declaration order 52 | Product p3 = {103, "Desk Chair", 149.99f, 8.75, true, 'F'}; 53 | 54 | printf("\nProduct 3 (ordered initializers):\n"); 55 | print_product(p3); 56 | 57 | // Method 4: Using a constructor-like function 58 | Product p4 = create_default_product(); 59 | 60 | printf("\nProduct 4 (default constructor):\n"); 61 | print_product(p4); 62 | 63 | // Method 5: Using a custom constructor function 64 | Product p5 = create_custom_product(105, "Coffee Mug", 12.49f, 0.4, true, 'H'); 65 | 66 | printf("\nProduct 5 (custom constructor):\n"); 67 | print_product(p5); 68 | 69 | // Demonstrate struct modification functions 70 | printf("\nIncreasing price of Product 1 by $50.00...\n"); 71 | increase_price(&p1, 50.0f); 72 | print_product(p1); 73 | 74 | printf("\nToggling stock status of Product 2...\n"); 75 | toggle_stock_status(&p2); 76 | print_product(p2); 77 | 78 | return 0; 79 | } 80 | 81 | // Function to print product details 82 | void print_product(Product p) 83 | { 84 | printf("ID: %d\n", p.id); 85 | printf("Name: %s\n", p.name); 86 | printf("Price: $%.2f\n", p.price); 87 | printf("Weight: %.2f kg\n", p.weight); 88 | printf("In Stock: %s\n", p.in_stock ? "Yes" : "No"); 89 | printf("Category: %c\n", p.category); 90 | printf("----------------------------\n"); 91 | } 92 | 93 | // Function to increase product price 94 | void increase_price(Product *p, float amount) 95 | { 96 | p->price += amount; 97 | printf("Price increased by $%.2f\n", amount); 98 | } 99 | 100 | // Function to toggle stock status 101 | void toggle_stock_status(Product *p) 102 | { 103 | p->in_stock = !p->in_stock; 104 | printf("Stock status toggled\n"); 105 | } 106 | 107 | // Constructor-like function for default product 108 | Product create_default_product() 109 | { 110 | Product p = { 111 | .id = 0, 112 | .name = "Unknown", 113 | .price = 0.0f, 114 | .weight = 0.0, 115 | .in_stock = false, 116 | .category = 'U'}; 117 | return p; 118 | } 119 | 120 | // Constructor-like function for custom product 121 | Product create_custom_product(int id, const char *name, float price, double weight, bool stock, char cat) 122 | { 123 | Product p; 124 | p.id = id; 125 | strncpy(p.name, name, sizeof(p.name) - 1); 126 | p.name[sizeof(p.name) - 1] = '\0'; // Ensure null-termination 127 | p.price = price; 128 | p.weight = weight; 129 | p.in_stock = stock; 130 | p.category = cat; 131 | return p; 132 | } -------------------------------------------------------------------------------- /Lab 08/Producer-Consumer1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // For sleep function 5 | 6 | #define BUFFER_SIZE 5 // Define the size of the buffer 7 | #define MAX_ITEMS 100 // Define the maximum number of items to be produced/consumed 8 | 9 | // Shared buffer and associated indices 10 | int buffer[BUFFER_SIZE]; 11 | int in = 0; // Index for the next item to produce 12 | int out = 0; // Index for the next item to consume 13 | int counter = 0; // number of items in the buffer 14 | 15 | // Counters for produced and consumed items 16 | int produced_count = 0; 17 | int consumed_count = 0; 18 | 19 | // Synchronization variables 20 | pthread_mutex_t mutex; // Mutex to protect shared data 21 | pthread_cond_t full; // Condition variable to signal when the buffer has items 22 | pthread_cond_t empty; // Condition variable to signal when the buffer has space 23 | 24 | // Producer thread function 25 | void *producer(void *arg) 26 | { 27 | int item = 1; // Start with item 1 and increment for each produced item 28 | 29 | while (produced_count < MAX_ITEMS) 30 | { 31 | // Lock the mutex to access shared variables 32 | pthread_mutex_lock(&mutex); 33 | 34 | // Wait until there is space in the buffer 35 | while (counter == BUFFER_SIZE) 36 | { 37 | pthread_cond_wait(&empty, &mutex); 38 | } 39 | 40 | // Produce an item and add it to the buffer 41 | buffer[in] = item; 42 | printf("Produced: %d\n", item); // Print the produced item 43 | item++; // Increment the item number 44 | in = (in + 1) % BUFFER_SIZE; // Update the index to the next position 45 | counter++; 46 | produced_count++; // Increment the count of produced items 47 | sleep(1); // Sleep for 1 second to simulate work 48 | 49 | // Signal the consumer that there is an item in the buffer 50 | pthread_cond_signal(&full); 51 | // Unlock the mutex 52 | pthread_mutex_unlock(&mutex); 53 | } 54 | 55 | pthread_exit(NULL); // Exit the thread 56 | } 57 | 58 | // Consumer thread function 59 | void *consumer(void *arg) 60 | { 61 | while (consumed_count < MAX_ITEMS) 62 | { 63 | // Lock the mutex to access shared variables 64 | pthread_mutex_lock(&mutex); 65 | 66 | // Wait until there is an item in the buffer 67 | while (counter == 0) 68 | { 69 | pthread_cond_wait(&full, &mutex); 70 | } 71 | 72 | // Consume an item from the buffer 73 | int item = buffer[out]; 74 | printf("Consumed: %d\n", item); // Print the consumed item 75 | out = (out + 1) % BUFFER_SIZE; // Update the index to the next position 76 | counter--; 77 | consumed_count++; // Increment the count of consumed items 78 | sleep(1); // Sleep for 1 second to simulate work 79 | 80 | // Signal the producer that there is space in the buffer 81 | pthread_cond_signal(&empty); 82 | // Unlock the mutex 83 | pthread_mutex_unlock(&mutex); 84 | } 85 | 86 | pthread_exit(NULL); // Exit the thread 87 | } 88 | 89 | // Main function 90 | int main() 91 | { 92 | pthread_t producerThread, consumerThread; // Thread identifiers 93 | 94 | // Initialize mutex and condition variables 95 | pthread_mutex_init(&mutex, NULL); 96 | pthread_cond_init(&full, NULL); 97 | pthread_cond_init(&empty, NULL); 98 | 99 | // Create producer and consumer threads 100 | pthread_create(&producerThread, NULL, producer, NULL); 101 | pthread_create(&consumerThread, NULL, consumer, NULL); 102 | 103 | // Wait for both threads to finish 104 | pthread_join(producerThread, NULL); 105 | pthread_join(consumerThread, NULL); 106 | 107 | // Destroy mutex and condition variables 108 | pthread_mutex_destroy(&mutex); 109 | pthread_cond_destroy(&full); 110 | pthread_cond_destroy(&empty); 111 | 112 | return 0; // Return success 113 | } 114 | -------------------------------------------------------------------------------- /Lab 11/Ex14_ProducerConsumer.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Thread-safe Buffer class that implements producer-consumer pattern 4 | * using wait-notify mechanism for proper thread synchronization. 5 | */ 6 | class Buffer { 7 | private int data; // Shared data between producers and consumers 8 | private boolean available = false; // Flag indicating if data is available for consumption 9 | 10 | /** 11 | * Produces a value and stores it in the buffer. 12 | * @param value The value to be produced 13 | * @throws InterruptedException if the thread is interrupted while waiting 14 | */ 15 | public synchronized void produce(int value) throws InterruptedException { 16 | // Wait while data is available (buffer is full) 17 | while (available) { 18 | wait(); // Releases lock and waits for consumer to consume 19 | } 20 | 21 | data = value; // Store the produced value 22 | available = true; // Mark buffer as having available data 23 | System.out.println("Produced: " + value); 24 | notifyAll(); // Notify all waiting consumers 25 | } 26 | 27 | /** 28 | * Consumes the value from the buffer. 29 | * @return The consumed value 30 | * @throws InterruptedException if the thread is interrupted while waiting 31 | */ 32 | public synchronized int consume() throws InterruptedException { 33 | // Wait while no data is available (buffer is empty) 34 | while (!available) { 35 | wait(); // Releases lock and waits for producer to produce 36 | } 37 | 38 | available = false; // Mark buffer as empty 39 | System.out.println("Consumed: " + data); 40 | notifyAll(); // Notify all waiting producers 41 | return data; // Return the consumed value 42 | } 43 | } 44 | 45 | /** 46 | * Demonstration of producer-consumer pattern with single producer and single consumer. 47 | */ 48 | public class Ex14_ProducerConsumer { 49 | public static void main(String[] args) { 50 | Buffer buffer = new Buffer(); // Shared buffer 51 | 52 | // Producer thread produces values 1 through 5 53 | Thread producer = new Thread(() -> { 54 | for (int i = 1; i <= 5; i++) { 55 | try { 56 | buffer.produce(i); // Produce value 57 | Thread.sleep(100); // Simulate production time 58 | } catch (InterruptedException ignored) { 59 | // Handle interruption (in this case, just ignore) 60 | } 61 | } 62 | }); 63 | 64 | // Consumer thread consumes 5 values 65 | Thread consumer = new Thread(() -> { 66 | for (int i = 1; i <= 5; i++) { 67 | try { 68 | buffer.consume(); // Consume value 69 | Thread.sleep(150); // Simulate consumption time 70 | } catch (InterruptedException ignored) { 71 | // Handle interruption (in this case, just ignore) 72 | } 73 | } 74 | }); 75 | 76 | producer.start(); // Start producer thread 77 | consumer.start(); // Start consumer thread 78 | } 79 | } 80 | /* 81 | Key Points: 82 | Thread Safety: All buffer operations are synchronized to prevent race conditions 83 | Wait-Notify Mechanism: 84 | - Producers wait when buffer is full (while (available)) 85 | - Consumers wait when buffer is empty (while (!available)) 86 | - notifyAll() wakes up all waiting threads 87 | 88 | Buffer State Tracking: available flag indicates whether data can be consumed 89 | Production/Consumption Rate: 90 | Producer sleeps 100ms between productions (faster) 91 | Consumer sleeps 150ms between consumptions (slower) 92 | Spurious Wakeups Protection: while loops guard against accidental wakeups 93 | Interruption Handling: Ignores interruptions for simplicity (real code might handle differently) 94 | 95 | This implementation ensures proper synchronization between producer and consumer threads, 96 | preventing both buffer overflow and underflow conditions. 97 | */ -------------------------------------------------------------------------------- /Lab 11/Ex18_ThreadLocalExample.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | import java.util.Map; 3 | 4 | public class Ex18_ThreadLocalExample { 5 | // ThreadLocal variable to store integer values 6 | static ThreadLocal threadLocal = ThreadLocal.withInitial(() -> 0); 7 | 8 | // Map to store thread results after they finish 9 | static Map threadResults = new HashMap<>(); 10 | 11 | public static void main(String[] args) throws InterruptedException { 12 | // Create an array to hold the threads 13 | Thread[] threads = new Thread[5]; 14 | 15 | // Create and start 5 threads 16 | for (int i = 0; i < 5; i++) { 17 | threads[i] = new Thread(new Task(), "Thread-" + (i + 1)); 18 | threads[i].start(); 19 | } 20 | 21 | // Wait for all threads to complete 22 | for (Thread thread : threads) { 23 | thread.join(); 24 | } 25 | 26 | // Print all thread results after they've finished 27 | System.out.println("\nThread results after completion:"); 28 | threadResults.forEach((name, value) -> 29 | System.out.println(name + ": " + value)); 30 | } 31 | 32 | static class Task implements Runnable { 33 | @Override 34 | public void run() { 35 | // Generate a random value for this thread 36 | int randomValue = (int)(Math.random() * 100); 37 | 38 | // Store it in thread-local storage 39 | threadLocal.set(randomValue); 40 | 41 | // Print the current value 42 | System.out.println(Thread.currentThread().getName() + " running: " + threadLocal.get()); 43 | 44 | // Store the result in the shared map before thread finishes 45 | synchronized (threadResults) { 46 | threadResults.put(Thread.currentThread().getName(), threadLocal.get()); 47 | } 48 | } 49 | } 50 | } 51 | /* 52 | Key Points: 53 | Creating 5 Threads: The code now creates and manages an array of 5 threads. 54 | Thread-Local Data: Each thread still maintains its own thread-local value. 55 | Storing Results: To access the data after threads finish, we use a synchronized Map to store each thread's result before it terminates. 56 | Thread Joining: The main thread waits for all worker threads to complete using join(). 57 | Result Access: After all threads finish, the main thread prints the collected results from the shared map. 58 | */ 59 | 60 | import java.util.HashMap; 61 | import java.util.Map; 62 | 63 | public class Ex18_ThreadLocalExample { 64 | // ThreadLocal variable to store integer values 65 | static ThreadLocal threadLocal = ThreadLocal.withInitial(() -> 0); 66 | 67 | // Map to store thread results after they finish 68 | static Map threadResults = new HashMap<>(); 69 | 70 | public static void main(String[] args) throws InterruptedException { 71 | // Create an array to hold the threads 72 | Thread[] threads = new Thread[5]; 73 | 74 | // Create and start 5 threads 75 | for (int i = 0; i < 5; i++) { 76 | threads[i] = new Thread(new Task(), "Thread-" + (i + 1)); 77 | threads[i].start(); 78 | } 79 | 80 | // Wait for all threads to complete 81 | for (Thread thread : threads) { 82 | thread.join(); 83 | } 84 | 85 | // Print all thread results after they've finished 86 | System.out.println("\nThread results after completion:"); 87 | threadResults.forEach((name, value) -> 88 | System.out.println(name + ": " + value)); 89 | } 90 | 91 | static class Task implements Runnable { 92 | @Override 93 | public void run() { 94 | // Generate a random value for this thread 95 | int randomValue = (int)(Math.random() * 100); 96 | 97 | // Store it in thread-local storage 98 | threadLocal.set(randomValue); 99 | 100 | // Print the current value 101 | System.out.println(Thread.currentThread().getName() + " running: " + threadLocal.get()); 102 | 103 | // Store the result in the shared map before thread finishes 104 | synchronized (threadResults) { 105 | threadResults.put(Thread.currentThread().getName(), threadLocal.get()); 106 | } 107 | } 108 | } 109 | } 110 | /* 111 | Key Points: 112 | Creating 5 Threads: The code now creates and manages an array of 5 threads. 113 | Thread-Local Data: Each thread still maintains its own thread-local value. 114 | Storing Results: To access the data after threads finish, we use a synchronized Map to store each thread's result before it terminates. 115 | Thread Joining: The main thread waits for all worker threads to complete using join(). 116 | Result Access: After all threads finish, the main thread prints the collected results from the shared map. 117 | */ -------------------------------------------------------------------------------- /Lab 07/struct in C.md: -------------------------------------------------------------------------------- 1 | # Demonstrating Struct Usage in C: 2 | 3 | Here's a complete C file that illustrates how to use structs with different variable types, initialization methods, and functions that operate on the struct: 4 | 5 | ```c 6 | #include 7 | #include 8 | #include 9 | 10 | // Define a struct with different variable types 11 | typedef struct { 12 | int id; 13 | char name[50]; 14 | float price; 15 | double weight; 16 | bool in_stock; 17 | char category; 18 | } Product; 19 | 20 | // Function prototypes (methods for the struct) 21 | void print_product(Product p); 22 | void increase_price(Product *p, float amount); 23 | void toggle_stock_status(Product *p); 24 | Product create_default_product(); 25 | Product create_custom_product(int id, const char* name, float price, double weight, bool stock, char cat); 26 | 27 | int main() { 28 | printf("=== Struct Example in C ===\n\n"); 29 | 30 | // Method 1: Initialize struct members one by one 31 | Product p1; 32 | p1.id = 101; 33 | strcpy(p1.name, "Laptop"); 34 | p1.price = 999.99f; 35 | p1.weight = 2.5; 36 | p1.in_stock = true; 37 | p1.category = 'E'; 38 | 39 | printf("Product 1 (initialized individually):\n"); 40 | print_product(p1); 41 | 42 | // Method 2: Initialize at declaration using designated initializers 43 | Product p2 = { 44 | .id = 102, 45 | .name = "Smartphone", 46 | .price = 699.99f, 47 | .weight = 0.3, 48 | .in_stock = false, 49 | .category = 'E' 50 | }; 51 | 52 | printf("\nProduct 2 (designated initializers):\n"); 53 | print_product(p2); 54 | 55 | // Method 3: Initialize in declaration order 56 | Product p3 = {103, "Desk Chair", 149.99f, 8.75, true, 'F'}; 57 | 58 | printf("\nProduct 3 (ordered initializers):\n"); 59 | print_product(p3); 60 | 61 | // Method 4: Using a constructor-like function 62 | Product p4 = create_default_product(); 63 | 64 | printf("\nProduct 4 (default constructor):\n"); 65 | print_product(p4); 66 | 67 | // Method 5: Using a custom constructor function 68 | Product p5 = create_custom_product(105, "Coffee Mug", 12.49f, 0.4, true, 'H'); 69 | 70 | printf("\nProduct 5 (custom constructor):\n"); 71 | print_product(p5); 72 | 73 | // Demonstrate struct modification functions 74 | printf("\nIncreasing price of Product 1 by $50.00...\n"); 75 | increase_price(&p1, 50.0f); 76 | print_product(p1); 77 | 78 | printf("\nToggling stock status of Product 2...\n"); 79 | toggle_stock_status(&p2); 80 | print_product(p2); 81 | 82 | return 0; 83 | } 84 | 85 | // Function to print product details 86 | void print_product(Product p) { 87 | printf("ID: %d\n", p.id); 88 | printf("Name: %s\n", p.name); 89 | printf("Price: $%.2f\n", p.price); 90 | printf("Weight: %.2f kg\n", p.weight); 91 | printf("In Stock: %s\n", p.in_stock ? "Yes" : "No"); 92 | printf("Category: %c\n", p.category); 93 | printf("----------------------------\n"); 94 | } 95 | 96 | // Function to increase product price 97 | void increase_price(Product *p, float amount) { 98 | p->price += amount; 99 | printf("Price increased by $%.2f\n", amount); 100 | } 101 | 102 | // Function to toggle stock status 103 | void toggle_stock_status(Product *p) { 104 | p->in_stock = !p->in_stock; 105 | printf("Stock status toggled\n"); 106 | } 107 | 108 | // Constructor-like function for default product 109 | Product create_default_product() { 110 | Product p = { 111 | .id = 0, 112 | .name = "Unknown", 113 | .price = 0.0f, 114 | .weight = 0.0, 115 | .in_stock = false, 116 | .category = 'U' 117 | }; 118 | return p; 119 | } 120 | 121 | // Constructor-like function for custom product 122 | Product create_custom_product(int id, const char* name, float price, double weight, bool stock, char cat) { 123 | Product p; 124 | p.id = id; 125 | strncpy(p.name, name, sizeof(p.name) - 1); 126 | p.name[sizeof(p.name) - 1] = '\0'; // Ensure null-termination 127 | p.price = price; 128 | p.weight = weight; 129 | p.in_stock = stock; 130 | p.category = cat; 131 | return p; 132 | } 133 | ``` 134 | 135 | ## Key Features Demonstrated: 136 | 137 | 1. **Struct Definition**: 138 | - Contains variables of different types (int, char array, float, double, bool, char) 139 | - Uses typedef for cleaner usage 140 | 141 | 2. **Initialization Methods**: 142 | - Individual member initialization 143 | - Designated initializers (clear and explicit) 144 | - Ordered initializers 145 | - Constructor-like functions (both default and custom) 146 | 147 | 3. **Struct Functions (Methods)**: 148 | - `print_product()` - displays all struct members 149 | - `increase_price()` - modifies a struct member via pointer 150 | - `toggle_stock_status()` - modifies a bool member 151 | - Constructor functions to create new instances 152 | 153 | 4. **Pointer Usage**: 154 | - Demonstrates passing struct by value and by reference 155 | 156 | To compile and run this program: 157 | ```bash 158 | gcc struct_example.c -o struct_example 159 | ./struct_example 160 | ``` 161 | 162 | This example shows both the basics and some more advanced patterns for working with structs in C. -------------------------------------------------------------------------------- /Lab 08/dining-philosopher.c: -------------------------------------------------------------------------------- 1 | // https://www.geeksforgeeks.org/dining-philosopher-problem-using-semaphores/ 2 | #include // Library for handling threads in C 3 | #include // Library for handling semaphores in C 4 | #include // Standard I/O library in C 5 | #include // Library for sleep function 6 | 7 | // Defining constants 8 | #define N 6 // Number of philosophers and forks 9 | #define THINKING 2 // Constant representing the "thinking" state 10 | #define HUNGRY 1 // Constant representing the "hungry" state 11 | #define EATING 0 // Constant representing the "eating" state 12 | 13 | // Macros to determine the philosopher to the left and right 14 | #define LEFT (phnum + (N - 1)) % N // Philosopher to the left 15 | #define RIGHT (phnum + 1) % N // Philosopher to the right 16 | 17 | // Array to hold the state of each philosopher (THINKING, HUNGRY, or EATING) 18 | int state[N]; 19 | 20 | // Array to hold the philosopher numbers (0 to N-1) 21 | int phil[N]; 22 | 23 | // Declaration of semaphores 24 | sem_t mutex; // Semaphore for mutual exclusion when accessing shared resources 25 | sem_t S[N]; // Semaphores for each philosopher, used to control their eating 26 | 27 | int numEater = 0;// Count of active eaters 28 | 29 | // Function to check if the philosopher can start eating 30 | void test(int phnum) 31 | { 32 | // If the current philosopher is hungry and both neighbors are not eating 33 | if (state[phnum] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING) 34 | { 35 | // Change state to eating 36 | state[phnum] = EATING; 37 | numEater++; 38 | // Simulate eating process (sleep for 2 seconds) 39 | sleep(2); 40 | 41 | // Print which forks the philosopher is taking and that they are eating 42 | printf("Philosopher %d takes fork %d and %d\n", 43 | phnum + 1, LEFT + 1, phnum + 1); 44 | printf("Philosopher %d is Eating\n", phnum + 1); 45 | 46 | // printf("no current Eating Philosophers = %d\n", nocurrentEating); 47 | 48 | // Signal the philosopher's semaphore to allow them to proceed 49 | sem_post(&S[phnum]); 50 | // sem_post(&S[phnum]) has no effect during takefork 51 | // used to wake up hungry philosophers during putfork 52 | } 53 | } 54 | 55 | // Function to simulate a philosopher taking forks 56 | void take_fork(int phnum) 57 | { 58 | // Lock the critical section using mutex to ensure mutual exclusion 59 | sem_wait(&mutex); 60 | 61 | // Set the state to hungry 62 | state[phnum] = HUNGRY; 63 | printf("Philosopher %d is Hungry\n", phnum + 1); 64 | 65 | // Check if the philosopher can eat 66 | test(phnum); 67 | 68 | // Unlock the critical section 69 | sem_post(&mutex); 70 | 71 | // If unable to eat, the philosopher waits for a signal 72 | sem_wait(&S[phnum]); 73 | 74 | // Simulate the time taken to pick up forks (sleep for 1 second) 75 | sleep(1); 76 | } 77 | 78 | // Function to simulate a philosopher putting down forks 79 | void put_fork(int phnum) 80 | { 81 | // Lock the critical section using mutex to ensure mutual exclusion 82 | sem_wait(&mutex); 83 | 84 | // Set the state to thinking 85 | state[phnum] = THINKING; 86 | numEater--; 87 | // Print that the philosopher is putting down forks and is thinking 88 | printf("Philosopher %d putting fork %d and %d down\n", 89 | phnum + 1, LEFT + 1, phnum + 1); 90 | printf("Philosopher %d is thinking\n", phnum + 1); 91 | 92 | // Test if the left and right philosophers can now eat 93 | test(LEFT); 94 | test(RIGHT); 95 | 96 | // Unlock the critical section 97 | sem_post(&mutex); 98 | } 99 | 100 | // Function representing the actions of a philosopher 101 | void *philosopher(void *num) 102 | { 103 | int f = 1; 104 | // Run indefinitely (simulate a philosopher's life cycle) 105 | while (1) 106 | { 107 | int *i = num; // Cast the argument to an integer pointer 108 | 109 | // Simulate thinking process (sleep for 1 second) 110 | sleep(1); 111 | 112 | // Try to take forks and eat 113 | take_fork(*i); 114 | 115 | // Simulate eating time 116 | sleep(0); 117 | 118 | // Put down forks after eating 119 | put_fork(*i); 120 | 121 | printf("number current Eating Philosophers = %d\n", numEater); 122 | f = 0; 123 | } 124 | } 125 | 126 | // Main function 127 | int main() 128 | { 129 | int i; // Loop variable 130 | pthread_t thread_id[N]; // Array to hold thread IDs for philosophers 131 | 132 | // Initialize the mutex semaphore with a value of 1 (binary semaphore) 133 | sem_init(&mutex, 0, 1); 134 | 135 | // Initialize the philosopher semaphores with a value of 0 (blocked initially) 136 | for (i = 0; i < N; i++) 137 | sem_init(&S[i], 0, 0); 138 | 139 | // Initialize Array to hold the philosopher numbers (0 to N-1) 140 | for (i = 0; i < N; i++) 141 | phil[i] = i; 142 | 143 | // Create philosopher threads 144 | for (i = 0; i < N; i++) 145 | { 146 | // Create a thread for each philosopher, passing the philosopher number as an argument 147 | pthread_create(&thread_id[i], NULL, philosopher, &phil[i]); 148 | 149 | // Print that the philosopher is thinking 150 | printf("Philosopher %d is thinking\n", i + 1); 151 | } 152 | 153 | // Join the philosopher threads (wait for them to finish, though they never do) 154 | for (i = 0; i < N; i++) 155 | pthread_join(thread_id[i], NULL); 156 | } 157 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CS306 : Operating Systems - Spring 2025 2 | 3 | --- 4 | 5 | 6 | 7 | 8 | ### Table of Contents 9 | - [CS306 : Operating Systems - Spring 2025](#cs306--operating-systems---spring-2025) 10 | - [Table of Contents](#table-of-contents) 11 | - [Lab Outline](#lab-outline) 12 | - [Assembly X8086](#assembly-x8086) 13 | - [Labs 1 and 2](#labs-1-and-2) 14 | - [Lab 3](#lab-3) 15 | - [Lab 4](#lab-4) 16 | - [Lab 5](#lab-5) 17 | - [Threads using C](#threads-using-c) 18 | - [Lab 6](#lab-6) 19 | - [Lab 7](#lab-7) 20 | - [Lab 8](#lab-8) 21 | - [Lab 9 (Practical Exam)](#lab-9-practical-exam) 22 | - [Threads using JAVA](#threads-using-java) 23 | - [Lab 10](#lab-10) 24 | - [Lab 11 (Self-Study)](#lab-11-self-study) 25 | - [Lab 12 (Practical Exam)](#lab-12-practical-exam) 26 | 27 | 28 | 29 | *** 30 | 31 | # Lab Outline 32 | 33 | ## Assembly X8086 34 | 35 | - We're using Emu8086 to simulate the execution of the assembly program. 36 | - You can download Emu8086 from here 37 | [Emu8086](https://archive.org/details/Emu8086V408r11) 38 | 39 | ### Labs 1 and 2 40 | 41 | - Basic Structure for Assembly X8086 program. 42 | - Basic instructions: **MOV**, **ADD**, **SUB** 43 | - Register VS Memory 44 | - Basic Registers: 45 | - **AX (AH + AL)** 46 | - **BX (BH + BL)** 47 | - **CX (CH + CL)** 48 | - **DX (DH + DL)** 49 | - How to set/initialize the registers with immediate value (hex, binary, or decimal) 50 | - Access different memory locations: 51 | - Data segment memory location. 52 | - Stack segment memory location. 53 | - Extra data segment memory location. 54 | - How to set bits using **OR** 55 | - How to clear bits using **AND** 56 | - How to invert bits using **XOR** 57 | - How to find 1's complement: using **NOT** 58 | - How to find 2's complement: using **NEG** 59 | - Swapping two operands using **XCHG** 60 | - More instructions: **MUL** and **DIV** 61 | - Define variables (initialized or not): 62 | - **db** (define byte = 8 bits). 63 | - **dw** (define word = 2 bytes = 16 bits). 64 | 65 | *** 66 | 67 | ### Lab 3 68 | 69 | - how to define an array (initialized or not): 70 | - array of bytes 71 | - array of words 72 | - How to access the array elements: 73 | - using **direct addressing** (or Using **direct-offset Addressing**). 74 | - using **index addressing**. 75 | - using **indirect addressing** by (**LEA** or **OFFSET**). 76 | - How to define **Label**. 77 | - Unconditional control instruction: **JUMP**. 78 | - **Loop** 79 | - Nested Loops. 80 | 81 | *** 82 | 83 | ### Lab 4 84 | 85 | - More exercises on using **Loop** and arrays. 86 | - More instrustions: 87 | - **CMP** 88 | - **JA** 89 | - **JG** 90 | - **CBW** 91 | - **CWD** 92 | - how different **FLAGS** are affected by some instructions: 93 | - **ZP**: Zero Flag. 94 | - **CF**: Carry Flag. 95 | - **OF**: Overflow Flag. 96 | 97 | *** 98 | 99 | ### Lab 5 100 | 101 | - More difficult exercises covering **Loop**, arrays, and conditional jump control instructions for unsigned and signed. 102 | - **PRINT** and **PRINTN** 103 | - More instrustions: 104 | - **ADC**: Add with Carry 105 | - **JC**: if CF = 1 then jump 106 | - **JNC**: if CF = 0 then jump 107 | - FYI: 108 | - Printing using **Video Mode**. 109 | - **PUTC** 110 | 111 | *** 112 | *** 113 | 114 | ## Threads using C 115 | 116 | ### Lab 6 117 | 118 | - Processes and Threads: Definitions and Differences 119 | - Threads vs Processes 120 | - Need for Multithreading 121 | - Features of Using Threads 122 | - Types of Threads 123 | - Thread Libraries 124 | - Creating and Assigning Work to Threads 125 | - Compile and Run C Files with Threads 126 | - Pointers & References. 127 | 128 | ### Lab 7 129 | 130 | - Struct Usage in C 131 | - How to use struct to pass multiple values to the thread function 132 | - Retrieve value from Thread function 133 | - Passing & Retrieving Multiple Values via Struct 134 | - Synchronization between Threads 135 | - Race condition 136 | - Deadlocks and Livelocks. 137 | - Common Synchronization Tools 138 | - **mutex (Mutual Exclusion)** 139 | - **semaphore** 140 | 141 | ### Lab 8 142 | 143 | - Case Studies 144 | - **Producer-Consumer** Problem with Mutex and Condition Variables 145 | - **Producer-Consumer** Problem with Semaphore 146 | - **Readers-Writers** Problem 147 | - **Dining-Philosophers** Problem 148 | 149 | ### Lab 9 (Practical Exam) 150 | 151 | *** 152 | *** 153 | 154 | ## Threads using JAVA 155 | 156 | ### Lab 10 157 | 158 | - Creating threads using **Thread** class 159 | - Creating threads using **Runnable** interface 160 | - Synchronizartion tools: 161 | - **volatile** keyword 162 | - **synchronized** keyword 163 | - **syncronized** method 164 | - **synchronized** block 165 | - locks 166 | - mutex 167 | - semaphores 168 | - condition variables 169 | - Creating Thread Pool using **ExecutorService** 170 | - Lambda expresssion 171 | - Using **Future** to wait for the returned value from a thread 172 | 173 | 174 | ### Lab 11 (Self-Study) 175 | 176 | 1. **Thread Priorities (Ex12)** 177 | - Setting thread priorities (`MIN_PRIORITY`, `NORM_PRIORITY`, `MAX_PRIORITY`). 178 | - OS-dependent scheduling behavior (no strict guarantees). 179 | 180 | 2. **Wait-Notify Mechanism (Ex13)** 181 | - Basic thread coordination using `wait()` and `notify()`. 182 | - Guarded blocks with `synchronized` and loop checks for spurious wakeups. 183 | 184 | 3. **Producer-Consumer Pattern (Ex14)** 185 | - Synchronized buffer with `wait()`/`notifyAll()`. 186 | - Handles empty/full states to prevent race conditions. 187 | 188 | 4. **ReadWriteLock (Ex15)** 189 | - `ReentrantReadWriteLock` for concurrent reads and exclusive writes. 190 | - Improves performance in read-heavy scenarios. 191 | 192 | 5. **CountDownLatch (Ex16)** 193 | - One-time synchronization: main thread waits for worker threads. 194 | - `countDown()` decrements; `await()` blocks until zero. 195 | 196 | 6. **CyclicBarrier (Ex17)** 197 | - Reusable barrier for thread synchronization at fixed points. 198 | - Optional barrier action triggers when all threads arrive. 199 | 200 | 7. **ThreadLocal (Ex18, Ex19)** 201 | - Thread-local variables for isolated per-thread storage. 202 | - Two approaches: shared `Map` (Ex18) vs. `Future`/`ExecutorService` (Ex19). 203 | 204 | 8. **Atomic Operations (Ex20)** 205 | - `AtomicInteger` for lock-free, thread-safe counters. 206 | - Methods like `incrementAndGet()` avoid race conditions. 207 | 208 | ### Lab 12 (Practical Exam) 209 | - Tuesday: May 13, 2025 210 | 211 | *** 212 | *** 213 | --------------------------------------------------------------------------------