Tuesday, July 29, 2025

CSUMB Week 28 (23 July 2025 - 29 July 2025)

Written below is a collection of my miscellaneous and scattered notes representing what I learned from this week:

- The difference between a thread and a process is that threads share the same memory whereas processes do not

- Thus, due to sharing the same memory, switching between threads is faster than when switching between processes

- Multiple threads can run at the same time within a program

- This can cause issues when threads interrupt and overwrite each other's steps (cause race issues)

- Part of this issue can be solved with a concept known as "locks"

- Locks is a general term for a mechanism that restricts/controls shared resources between threads

- A Mutex is a specific category of lock that deals with allowing only one thread to run at a time

- However, the benefit to using threads is due to parallelism (to speed up time by doing different parts of the task at the same time)


Also including what I wrote for this week's discussion topic:

    "A program is said to be indeterminate when we do not know what the program's true outcome will be. For example, it might give us a random answer within a certain range/spectrum. This happens when internal processes can interfere with each other. A great example, based on this weeks reading, is when we run two threads at the same time (and thus leading to a race condition). 

    To provide greater detail, let's say we have two threads trying to update the same variable called "counter." Each thread is to add up the counter by 10 times. Intuitively we believe the final result should be 20 since two threads would mean 10 + 10 = 20. However, every time we run the program, we might get the answer as 17, or 19, or 18, etc. This is because one thread may interrupt the step of another thread before that thread completes its update (thus overwriting that thread's intended action). To provide a visual, let's say there are three steps that a thread will go through:

1. Read the counter

2. Add +1 to the counter

3. write the value back to the counter

    This means before a thread can complete all three steps, another thread can interrupt it at any of these steps and overwrite over it (thus leading to an counter increment getting lost). This specific example is called a race condition because it depends on which of the thread gets to the steps first (and who interrupts each other first)."

Monday, July 21, 2025

CSUMB Week 27 (16 July 2025 - 22 July 2025)

Written below is a collection of my miscellaneous and scattered notes representing what I learned from this week:


[In regard to topic involving pages]

- The term "page" is used to represent a chunk of space from the virtual memory space 

- The term "page frame" is used to represent a chunk of space from the physical memory space

- Generally, each "page" must correspond to a "page frame" (it is a 1 to 1 relationship) (only true if every page is mapped to a RAM) 

- Scenario that falls outside of "generally" is when a page may not be mapped from a RAM (e.g. could come from a hard drive disk instead) or maybe a page is not mapped at all to begin with.


[In regard to topic involving virtual and physical memory space]

- A virtual memory space does not represent a block of contiguous memory from the physical memory space.

- Instead, virtual memory space is when multiple small chunks (called pages), 

    - mapped from either physical memory (called a RAM) 

    - or mapped from other areas (such as hard drive disk), 

    - or even an unmapped page (reserved pages), 

are all virtually mapped together into a "fake" contiguous block of memory to give an illusion of a contiguous memory block.

- Metadata about a particular page is called a Page Table Entry (PTE), 

- PTE itself is located within a small section of memory reserved just for them called a Page Table


[The overall structure/framework of virtual address space]

- a "virtual address space" is composed of "pages" 

- and each of these "pages" are composed of "memory locations" that can hold certain data size (e.g. 1 byte [8 bits] for each "memory locations") 

- and a "memory location" contains "memory data" (example of memory data: 0b10101100) 

- and "memory address" points to a specific "memory location" 

- and "memory address" is composed of "VPN" and "offset"

- and "memory address" IS NOT part of the "memory data" found within a "memory location"

So technically the term "virtual address space of 64 bytes" (found in our first lecture slide) means: 

- "A virtual memory space that is composed of 64 memory locations, each containing 1 byte worth of memory data"

Tuesday, July 15, 2025

CSUMB Week 26 (9 July 2025 - 15 July 2025)

This week for CST 334 was frustrating. The number of times I've flipflopped between 

"I do not understand pointers"

and

"I do understand pointers"

has been staggering. I think the main problem is not necessarily in understanding the definition of what a pointer is (that I understand - a pointer is just a variable that points to another variable's memory address where its actual data is stored), but rather the practice of reading and writing them comfortably in a given code. While I understand the definition, sometimes I freeze up when I "visually" try to make sense of how it actually works when I see (*variable) or *(*(variable)) as I try to "map" out who's related to who. It is rather easy to get lost. 

However, a satisfying part of this week is that I feel more comfortable in my understanding of memory diagrams and how computer memory actually functions. I now understand the concept of virtual memory while I am still trying to make sense of segmentation and topics involving free space management such as memory allocation to a greater detail. Dr. Ogden's videos are actually really helpful, and I should find a way to download or preserve them for personal future reference. 

With that being said, my small victory there ended the moment I started to work on assignment #3. I've realized just how weak my reading skill is when it comes to the C language. Once again, it was easy to become lost amongst all the pointers usage. Every function utilized one and each node had their own pointers forward and backward. I think I've also had to deal with what is called as "pointer arithmetic"? Or was it called "type arithmetic"? It involved type casting certain pointers to a certain type to perform arithmetic operations then typecast back to the original. That definitely gave me a good run session as I poured over tutorial videos on YouTube. 

Tuesday, July 8, 2025

CSUMB Week 25 (2 July 2025 - 8 July 2025)

This week I learned that a single core on a CPU can only technically handle and run 1 process at a time; however, with context switching, it gives the illusion that a single core can run multiple processes at once. The fact that a CPU core can do this thousands of times per second to give us an illusion of a seamless operation blows my mind. 

Context switching involves CPU scheduling algorithms such as Round Robin, FIFO, SJF, etc. which determines which process should run next when a context switch does occur. I've also learned how to calculate these algorithms in a small-scale scenario when given a # of processes, an entry time, and duration to help me grasp a better understanding of how response time and turnaround time (TAT) are obtained and how they differ based on the scheduling algorithms are utilized. 

This week, I've also continued to learn more about C syntaxes and ran small demos on my MacBook to test and practice some of the concepts mentioned in the lecture videos. One of them was using the fork() function to create a process tree. In my practice code, I wrote:

pid_t childPid = fork();

char character = 'A';

if (childPid < 0) {

    printf("forking process failed\n");

}

if (childPid > 0){

    printf("This is the parent process.\n");

    printf("process_ID (PID): %d\n", childPid);

    printf("%c\n", num); 

    printf("end of process.\n\n");

}

if (childPid == 0){

    printf("This is the child process.\m");

    printf("pricess_ID (PID): %d\n", childPid);

    printf("%c\n", character);

    printf("end of process\n\n");

}

return 0;


I wrote this code to show how the PID number differs between a parent and a child process and how to separate them if I wanted to run a command/task for just one of those process (rather than running the same command simultaneously by all present processes). I then ran my code using a clang compiler on a zsh shell.

Tuesday, July 1, 2025

CSUMB Week 24 (21 June 2025 - 1 July 2025)

Write a 1 - 2 paragraph journal post, of at least 250 words, of what you learned this week in CST 334.

Man, where do I even start with this. Before I even begin talking about the C language itself (which I have never touched until this week), I want to state that I spent quite a while conceptually learning how Docker works. Apparently a docker image is just a fancy way of saying "here's a large folder that just contains the software code with all of its relevant files needed to run it (e.g. the correct java version, etc.)." A docker container is just a fancy word for "and here's a mini virtual environment that serves as a single instance of the image being run."

I then had to learn how to feel comfortable using a command terminal (Windows PowerShell) and be familiar with its relevant script lines/commands. 

Then I began to learn the basics of C, including struct, pointers, and its relevant memory shenanigans. In particular, I had a hard time fully understanding pointers. But now I understand that (as I wrote in the first discussion week):

"a pointer variable stores the memory address of the original variable it points to. Therefore, as an example, the pointer variable named ptr that points to the original variable called var will contain the same memory address that var utilizes to store its data. In other words: ptr and var are located in their own respective differing memory address, but the data content of ptr is the memory address that var uses to store its own data.

But the problem is, the content of ptr can indicate either both a proper int number (if ptr was actually just a normal int variable) or a valid memory address (if ptr actually is a pointer). For example, the content of ptr can be 0x000004D2. This can either indicate the number 1234 or the memory at address 0x000004D2. Therefore, you cannot reliably tell if a variable is a pointer by examining its content alone."