Windows 10 System Programming, Part 1 - podcast episode cover

Windows 10 System Programming, Part 1

May 23, 202538 min
--:--
--:--
Download Metacast podcast app
Listen to this episode in Metacast mobile app
Don't just listen to podcasts. Learn from them with transcripts, summaries, and chapters for every episode. Skim, search, and bookmark insights. Learn more

Episode description

These Book offer an in-depth look at Windows system programming, primarily focusing on processes, threads, memory management, and file I/O. They explain fundamental concepts like what a process is, how threads function within processes, and the use of handles to interact with system objects. The excerpts cover topics such as managing thread scheduling through priorities and affinities, different methods for inter- and intra-process synchronization, and utilizing thread pools for efficient task execution. Additionally, they explore memory organization within a process and how to interact with the file system and various devices programmatically.

You can listen and download our episodes for free on more than 10 different platforms:
https://linktr.ee/cyber_security_summary

Get the Book now from Amazon:
https://www.amazon.com/Windows-10-System-Programming-Part/dp/B08X63B6VP?&linkCode=ll1&tag=cvthunderx-20&linkId=0336bdc52734cce3300e399d01c9058f&language=en_US&ref_=as_li_ss_tl



Discover our free courses in tech and cybersecurity, Start learning today:
https://linktr.ee/cybercode_academy

Transcript

Speaker 1

Welcome to the deep dive. Today. We're really peeling back the layers of your Windows ten computer.

Speaker 2

Yeah, going straight to the core.

Speaker 1

Exactly how software actually interacts with the operating system. One of you asked for a deeper look, and well, here.

Speaker 2

We are, absolutely and we've got a really good technical book to guide us. We'll be digging into the key insights on the fundamental stuff.

Speaker 1

Like processes, threads.

Speaker 2

Right, memory management, and that crucial world of IO input output operations.

Speaker 1

Our mission then for this deep dive is to get right to the heart of how Windows actually juggles all the programs you run and the resources they all need.

Speaker 2

We're aiming for those moments where it just clicks.

Speaker 1

Yeah, those aha moments where you think, oh, that's why my system does that. So let's start at the very beginning processes.

Speaker 2

Okay, so book right away makes this really important point. It might even surprise you. We usually think of a process as the thing that's running, but it's actually more accurate to think of it as a management object, a container. Basically, I contain yeah, the actual work, the code execution that's done by threads within the process.

Speaker 1

Okay, So processes are like maybe office buildings, and threads are the workers inside.

Speaker 2

That's a great analogy. Exactly one can't really function without the other, but they definitely have distinct roles.

Speaker 1

Interesting, So if the process isn't the runner, what does it actually own what's inside this office building?

Speaker 2

Well, a process is responsible for some critical things. First, it gets its own private address space. Think of it like its own dedicated chunk of memory, its floor plan. Okay. Then it holds one or more threads, the workers. It also keeps a handle table.

Speaker 1

A handle table like an inventory list short of.

Speaker 2

Yeah, yeah, an inventory of all the system resources it's using. And critically, it's assigned a unique process ID.

Speaker 1

Or PID PIDs. Right, we see those in task Manager all the time. Now, the book says they're unique but also reusable. How does that work? I sort of assumed a PID was like permanent.

Speaker 2

Yeah, that's common thought. But the key thing is a PID uniquely identifies a currently running process.

Speaker 1

Ah only while it's active.

Speaker 2

Exactly as long as that kernel object representing the process exists, the PID is its tag. But once the process finishes, poof that kernel object is gone.

Speaker 1

And the number can be used again.

Speaker 2

Later, right for a completely different new process it's like reusing raffle ticket numbers for different draws.

Speaker 1

That makes total sense, and it's a good reminder. Then, when we see say multiple Chrome Windows Open or Word instances, each one is its own distinct process, with its own PID, its own resources, even though they all started from the same program file.

Speaker 2

Precisely, the dot exc file is the blueprint, but each running instance gets its own private stuff. Now about that address space, the private memory. Yeah, the book lays out some different sizes. It depends on whether it's a sixty four bit or a thirty two bit process.

Speaker 1

Right. For sixty four bit processes on sixty four bit Windows, we're talking massive amounts of space, right, like eight terabytes or even one hundred and twenty eight.

Speaker 2

Terrabyte, Yes, staggering numbers. Eight terabytes on Windows eight and earlier, and then one hundred and twenty eight terabytes from Windows eight point one onwards. It's like having an almost infinite address book.

Speaker 1

Okay, but what about those older thirty two bit programs, the one still running on our modern sixty four bit systems.

Speaker 2

Ah Okay, that's where it gets a bit more nuanced. By default, a thirty two bit process only gets a two gigabyte address.

Speaker 1

Space only two gigs.

Speaker 2

But if the program was built with a special flag, a setting called large address aware.

Speaker 1

Large address aware.

Speaker 2

Yeah, if it has that flag, it can actually access up to four gigabytes on a sixty four bit system.

Speaker 1

So it doubles its potential memory pretty much.

Speaker 2

Think of the flag as the thirty two bit program telling the sixty four bit system, Hey, I know how to handle more memory addresses than usual.

Speaker 1

Okay, so that flag signals it's ready for more space. Now. Another key piece here seems to be these dynamic link libraries DLLs.

Speaker 2

They're everywhere we really are. Dls are essentially packages. They contain codeta resources things a program might need, and they get loaded into a process dynamic or dynamically, meaning either when the process starts up that's called static linking even though it sounds contradictory, or later on when the process explicitly asks for it, which is true dynamic linking.

Speaker 1

The book mentions you can't just run a DLL directly, right because they don't have that main entry point like an executable.

Speaker 2

Correct, no main function. But the really interesting part and a big efficiency thing is the memory sharing.

Speaker 1

Ah, yes, tell me about that.

Speaker 2

So when multiple processes are using the same DLL, especially those common Windows DLLs in the system thirty two folder.

Speaker 1

Like kernel thirty two dot dll.

Speaker 2

Exactly or User thirty two dot DLL. The actual code from the DLL can be shared in physical.

Speaker 1

RAM, so you don't have multiple copies loaded, right.

Speaker 2

It avoids wasting precious RAM. It's a huge win.

Speaker 1

And these particular DLLs, the subsystem ones, they're the ones that actually implement the core Windows API. Aren't they the functions that applications call to talk to the OS.

Speaker 2

That's precisely it. They're the gateway for norm user mode applications to access the underlying power of the Windows kernel. And this focus is really what the book is all.

Speaker 1

About, which leads us nicely into the broader Windows architecture user mode versus kernel mode.

Speaker 2

User mode is where our everyday apps live, Notepad, your browser games, plus those subsystem DLLs we just talked about, and also something called win.

Speaker 1

RT and kernel mode is the deeper layer, the engine room.

Speaker 2

Correct, that's the privileged part of the OS where the core components run, managing hardware security, that kind of thing.

Speaker 1

So user processes, subsystem DLLs and win RT, what's.

Speaker 2

That win RT or Windows run Time is a newer API layer. It came in with Windows eight, mainly for those Universal Windows Platform apps UWP apps.

Speaker 1

The ones from the Microsoft Store mostly.

Speaker 2

Yeah, it's built on an older technology called comm Component Object Model, which is all about software components talking to each other. And win RT supports multiple programming languages.

Speaker 1

Interesting, and it's not just for UWP apps. No.

Speaker 2

Recently a subset of win rts is actually available for traditional desktop applications too. Seems like Microsoft is trying to bridge the gap between those two worlds.

Speaker 1

Makes sense now for anyone listening who's thinking about actually doing some Windows system programming. The book mentions Duols Visual Studio primarily.

Speaker 2

Yeah, Visual Studio is the main integrated development environment the ID. The book emphasizes just getting your development set up right from the start.

Speaker 1

And it mentions that even doing a basic Hello World application can teach you something.

Speaker 2

Absolutely. Just compiling it shows you the process and you might notice subtle differences depending on whether you build it for a thirty two bit system that's by eighty six or a sixty four bit system by sixty four.

Speaker 1

Okay, And following on from that, character encoding Unicode this sounds important.

Speaker 2

It's crucial, especially for software that needs to work globally. There's a Unicode setting usually set by default and visual studio when you.

Speaker 1

Compile, and that affects how strings are handled.

Speaker 2

Yes, yes, it determines whether a type like lpctstr in the code represents text using UTFS sixteen, which can handle pretty much any character from any language, or the much more limited ASCI standard.

Speaker 1

So UTS sixteen is generally preferred definitely, and.

Speaker 2

You see this directly in the Windows API functions themselves. A function like creep mutex, for example, isn't really one function. Well, it's like a macro. The compiler expands it to either create mutex WZ the WS for wide characters UTF sixteen, or create mutexa A for ANSI or ASCI ah.

Speaker 1

Okay, So using Unicode means you automatically get the w versions, which prevents your text getting garbled if it contains non English characters.

Speaker 2

Exactly. It voids data loss and makes your software work correctly with international text, absolutely vital these days.

Speaker 1

The book also flags safer ways to handle strings right like wccswise.

Speaker 2

Yes and functions from the struceay dot EA CHEDDAR. It's quick reminder that the old C style string functions can be risky, you know, buffer overflows and security issues. These newer functions are designed to be much safer.

Speaker 1

Good practice to use them and for the code example. In the book, it mentions helper libraries WISHL and WTL.

Speaker 2

Yeah, the Windows Implementation Library WIL and Windows Template Library WTL. They basically provide convenience C plus plus wrappers around the raw Windows API.

Speaker 1

Makes things less tedious pretty.

Speaker 2

Much save if you write in a lot of boilerplate code. Makes development quicker and less error prone. The book also touches on Hungarian notation.

Speaker 1

Oh yeah, that naming convention like hend for a window handle exactly.

Speaker 2

Or else dir for a pointer to a string. It's an older style you'll see in the Windows API documentation. In older code, it embeds the variable type.

Speaker 1

In the name, A bit of a historical thing. You don't have to use it in new code.

Speaker 2

No, not really, It's just good to recognize you when you see it. Okay, So moving on. No system programming discussion is complete without error handling. What happens when things go wrong?

Speaker 1

Right? How does the Windows API tell you something failed?

Speaker 2

There are a few common patterns you'll see. Functions return a bool. Generally, non zero means success es.

Speaker 1

Zero means failure, but don't check for exactly true.

Speaker 2

Right The book warms about that success might be one, or might be two or something else non zero, Just check if it's zero or not. Think you have types like l status or long. With those, zero usually means success. The constant error success is actually zero. Any positive value indicates a specific.

Speaker 1

Error code, an h result.

Speaker 2

A result is common two, especially with Calm and Newer APIs zero or positive generally means success as okay is zero and negative values signal different errors.

Speaker 1

So when a function does fail, how do you find out why?

Speaker 2

The main way is to immediately call to get last air function immediately Yes, because the next API call might overwrite the error code and critically get laster gives you the error code for the current thread.

Speaker 1

Ah, So each thread has its own last error value precisely.

Speaker 2

If you have multiple threads, you can assume one thread's error relates to another's failure. It's threads specific.

Speaker 1

Got it? Okay? What about finding out Windows version? The book says the old way get version X is kind of deprecated now.

Speaker 2

Yeah, it's not recommended for various reasons related to compatibility settings. The modern approach is better, which is there's a header file version all PRIs dot age with a bunch of simple functions like is Windows expra, greater, is Windows ten or greater is when a server and so on.

Speaker 1

They just return true or false.

Speaker 2

Exactly, much cleaner for most common version checks. Under the hood they use a more fundamental function called verify version info. Usually the helpers are all unique.

Speaker 1

Okay, nice and simple, right, let's ship gears. Objects and handles. These sound absolutely central to Windows.

Speaker 2

They are fundamental. Handles are everywhere. The book describes them as basically identifiers for kernel objects.

Speaker 1

Kernel objects being what kinds of things.

Speaker 2

These are the core resources managed by the Windows kernel itself, things like files you open, processes that are running threads doing work, synchronization tools like Mutex's events, all the basic building.

Speaker 1

Blocks, okay, And the handle is how our program.

Speaker 2

Refers to them, exactly. It's an abstract token, like a ticket or a claim check. Your user mode program uses the handle to tell the kernel which object it wants to.

Speaker 1

Interact with, so it provides a layer of abstraction and security.

Speaker 2

Yes, you don't get direct access to the kernel's internal data structures. You operate through the handle.

Speaker 1

So when we call say, create mutechs to make a synchronization object.

Speaker 2

If it works, you get back a handle value, a number basically that represents that mutex object living down in the kernel. And if it fails, the return values usually zero or null. And then there's open mutex, which is specifically for getting a handle to a mutex that already exists and has a name.

Speaker 1

Right. Create mutex is interesting because if you give it a name, it can either create a new named mutex or it can open an existing one with that name.

Speaker 2

How do you know what happened?

Speaker 1

Even if create mutex succeeds in opening an existing one, if you call get last ray after, it will return error already.

Speaker 2

Exists, ah okay, whereas open mutex just fails if the name mutex.

Speaker 1

Isn't there, correct, it won't create one for you.

Speaker 2

Now, the book breaks down what's sort of conceptually in a handle, A pointer to the object and access mask and flags.

Speaker 1

Yeah, that's a simplified view. The access mask is super important. It defines what operations you're actually allowed to perform using that specific handle, like permissions exactly. For instance, if you want to terminate another process. You first need a handle to it. You get that using open.

Speaker 2

Process, but when you call open process you have to explicitly request the process terminate access right. If the handle you get back doesn't have that right in its access mask, then calling terminate process with that handle will just fail.

Speaker 1

So the handle encodes the permissions. What about the flags inheritance Protection from close.

Speaker 2

Inheritance means whether a child process created by this process automatically gets a copy of the handle. Protection from close handle flag protects from close is a safety feature makes it harder to accidentally close a really important handle.

Speaker 1

Can you change these flags?

Speaker 2

Yes, using set handle information and get handle information. And if you really want to see all the handles a process has.

Speaker 1

Open process explorer.

Speaker 2

Process Explorer from cysinternals is the tool. It's invaluable. It shows the handle value, the type of object, file, thread, mutex its name if it has one, the object's address in kernel memory, the raw access mask, and even a decoded human readable version of the access rights like looking at the process's internal toolkit.

Speaker 1

Definitely a must have tool. Now, managing these handles in code, especially C plus plus plus A, seems error prone. The book introduces a smart handle wrapper class.

Speaker 2

Yes, it demonstrates a concept called r AII. R AI resource acquisition is initialization. It basically means the handle resource is acquired when the C plus plus wrapper object is created, and crucially, it's automatically released. The handle is closed when the wrapper object goes out of scope or is destroyed.

Speaker 1

Ah, so it cleans up after itself. Prevents handle leaks exactly.

Speaker 2

It makes handle management much safer and easier. The example class also prevents axidel copying of handles, but allows transferring ownership using something called move semantics. Very useful C plus plus features neat.

Speaker 1

Okay, What about object naming and sessions? Names aren't always global usually?

Speaker 2

Know when your regular user application creates a named object like a name mutex, that name is typically only visible within your current user login session.

Speaker 1

So another user logged in wouldn't see it.

Speaker 2

Correct unless you specifically create it in the global name space.

Speaker 1

How do you do that?

Speaker 2

You prefix the name with global like global mouse, shared, mutechs. These live in a special base named objects directory in the kernel's object manager name space.

Speaker 1

Can any application do this?

Speaker 2

Well, there's a catch. Modern sandbox apps called app containers usually don't have the permissions to create objects in the global name space. It's mainly for services or older desktop apps needing system wide coordination.

Speaker 1

So if you have two separate programs, maybe even started by different users, they could use these global named objects to communicate or synchronize.

Speaker 2

Yes, that's a primary use case. One process creates the named object, create mutex with the global name, and another process can open it using the same name, open mutext, or even create utechs. Again, the name acts is the rendezvous point.

Speaker 1

Interesting. Another mechanism mentioned is handle duplication using duplicate handle. What's that about?

Speaker 2

This lets you take a handle you have in your process and create a new handle, potentially in a different process that refers to the exact same underlying kernel object.

Speaker 1

Why would you do that?

Speaker 2

A common reason is when a parent process starts a child process, the parent might want to give the child access to one of its own open handles, like maybe it's standard input or output pipe, So.

Speaker 1

You duplicate the parent's handle into the child's process space.

Speaker 2

Exactly, you need a handle to the target process with the process you panel permission to do this. You can even duplicate a handle within the same process if you need another handle to the same objects, maybe with different access rights.

Speaker 1

Okay. The book then briefly mentions user objects Windows menus and GDI objects bitmaps, fonts. They're handled a bit differently.

Speaker 2

Yeah. User objects like Windows don't use reference counting in the same way kernel objects do. The first process to destroy one affects everyone sharing it and their handles their scope to something called a Windows station, which also manages things like the clipboard for applications on.

Speaker 1

The same desktop, and GDI objects.

Speaker 2

Managed by the GDI subsystem, a separate part of Windows.

Speaker 1

This is giving us a really solid grounding. Now the book starts talking about different types of processes. Protective processes light PPL sounds like a security thing.

Speaker 2

It is introduced in Windows eight point one. PPL provides enhanced protection, making these processes much harder to tamper with or terminate, even for administrators like antivirus software. That's a key example. Yes, anti malware services often run as PPLs to protect themselves from malicious software trying to shut them down. There are different protection levels within PPL.

Speaker 1

Then there are minimal processes Windows ten features. These sound really stripped down.

Speaker 2

They are. They start with a completely empty address space, no executable no DLLs initially mapped, super lightweight.

Speaker 1

What uses them?

Speaker 2

The registry process is one example. Another key one is the memory compression process, which works behind the scenes to optimize RAM usage.

Speaker 1

Memory compression I might not see that in task manager.

Speaker 2

Sometimes it is hidden or aggregated, but Process Explorer will definitely show it. These minimal processes are typically created directly by the kernel itself.

Speaker 1

Fascinating how processes are evolving. The book also clarifies that PIDs are just special handle values internally, and it covers the statuses running suspended and not responding. Not responding is just for GUI apps, right correct.

Speaker 2

It happens when the main UI thread gets stuck and doesn't process window messages for about five seconds or more. Command line apps never show not responding, okay.

Speaker 1

The book then mentions PE files portable executable, the format for dot exe and dot dll files, and how they list their dependencies the other DLLs they.

Speaker 2

Need right in the import table. And when you launch a program, the Windows loader has a specific search path that follows to find those needed DLLs.

Speaker 1

What's the order it checks known.

Speaker 2

DLLs first, special system ones, then the application's own directory, then the current directory, then the main system directory System thirty two or siswas sixty four, and finally all the directories in the system's path.

Speaker 1

Environment variable and if it can't find one, you get.

Speaker 2

That dreaded air message box and the process usually fails to start. Dependency loading is critical.

Speaker 1

Then we get to actually starting processes create process. Wow. Look at all those parameters.

Speaker 2

It's like the master control panel for launching applications. You specify the command line security settings, whether handles are inherited, creation flags.

Speaker 1

Creation flags like creating new console or create suspended exactly.

Speaker 2

Also the environment variables, the starting directory, the startup INNEFO structure which controls the window appearance, and you get back the handles and IDs in the process information structure. Huge amount of control.

Speaker 1

And process priority classes affecting thread priorities.

Speaker 2

Yes, ranging from idle up to real time. Most apps run at normal setting. Real time usually needs admin rights because it can really impact system responsiveness if misused.

Speaker 1

That startup infos structure too, controls window size position, whether it's shown, minimize, maximized, even redirecting standard input out pewter.

Speaker 2

It's how a parent process shapes the initial state of its child. The book also gives a nod to a useful visual studio extension for debugging child processes and reminds us again you can't just launch UWP apps like normal executables.

Speaker 1

Right, They need that special activation mechanism, which brings us back to PPL again briefly.

Speaker 2

Just reinforcing that they have different signer levels, restricting access even preventing termination by admins. You can see the protection level and process explorer. The book shows. Trying to launch calculator fails if you just copy its command line.

Speaker 1

Because it's a UWP app needs the proper.

Speaker 2

Launch exactly, which involves using those Windows run Time win rt API. As we mentioned, the I Application Activation Manager interface is key. Using methods like activate application, you often need the app's full package name.

Speaker 1

Okay. Then a quick mention of minimal and PICO processes. Again, minimal are kernel created. PICO processes are for things like the Windows subsystem for Linux WSL translating Linux calls.

Speaker 2

Right, but not the main focus here?

Speaker 1

Then, how processes end three ways? All threads exit exit processes call or termain it process from outside.

Speaker 2

Pretty much even when your main function returns. In CC plus plus two, the runtime library calls exit process from the kernel's view the process ends when its last thread terminates.

Speaker 1

And getting info about a running process, get exit code process, get process times for CPU usage.

Speaker 2

Query full process image name. To get the executable path, you need to allocate a buffer for that one.

Speaker 1

And listing all processes. The tool help thirty two snapshot functions.

Speaker 2

Create tool help thirty two snapshot process thirty two first, process thirty two next. That gives you the basics like PID in name for everything running.

Speaker 1

But to do more like terminate or get detailed info, you need open process first.

Speaker 2

Yes, and you need to request the right access permissions. It might fail for protected system processes. Air five is access denied. AIR eighty seven often means invalid parameter. Maybe the PID doesn't exist anymore.

Speaker 1

Debug privilege helps.

Speaker 2

Sometimes yes, it lets you open more processes running elevated and visual Studio often grants it implicitly. For even more detail, there's WTS enumerate process X.

Speaker 1

What does that give you things like.

Speaker 2

The username, session id, detailed CPU times, handle counts, threadcounts, or rich review.

Speaker 1

Okay, that's a lot on processes. Let's talk about jobs, grouping processes exactly.

Speaker 2

Job objects let you manage a set of processes as a single unit Process Explorer actually shows if a process is in a job, how do you use them? Create one with the separate job object, then add processes to it using assigned process to job object. You can even have hierarchies of jobs.

Speaker 1

But the real power is restrictions.

Speaker 2

Definitely. Using set information job object, you can set limits on the entire group of processes in the job, things like total CPU time, total memory commitment.

Speaker 1

You can limit UI interactions too, like blocking clipboard access.

Speaker 2

Yes, there are UI restrictions you can apply the book mentions a sample app job monitor that lets you play with this, like limiting notepad CPU or blocking certain actions.

Speaker 1

CPU rate control is newer Windows eight plus.

Speaker 2

Reret Right, let's you set a hard percentage limit on the CPU usage for all processes in the job combined. Very useful for resource management and sandboxing.

Speaker 1

Okay, super useful concept. Now let's dive into threads. We said these are the actual workers inside a process.

Speaker 2

Yes, the independent paths of execution. They allow a single process to do multiple things concurrently, potentially using multiple CPU cores.

Speaker 1

You create them with create thread. Need to give it a starting function, right.

Speaker 2

The threads entry point function plus an optional parameter to pass to it, stack size settings, creation flags like create suspended if you don't want to run immediately and you get back a handle and a thread ID.

Speaker 1

Tids are unique system wide like PIDs.

Speaker 2

Yes. The book also mentions HyperThreading as MT, where one physical core looks like multiple logical processors to the OS.

Speaker 1

Can boost performance, but potential cache issues can be.

Speaker 2

Yeah, threads on the same physical core might compete for cash. You see logical processors and task manager usually can disable SMT in the bios if needed.

Speaker 1

Now, terminating threads termat thread sounds.

Speaker 2

Bad, very bad. Generally it's abrupt. Kills the thread instantly without cleanup can lead to resource leaks, deadlocks, corrupted data. Much better to signal the thread to exit gracefully itself. Okay.

Speaker 1

Threads have stacks for local variables and handles like processes. You get one from create thread or open thread right.

Speaker 2

Open thread is like open process needs a TID in permissions. Interestingly, threads don't have a built in name property in the kernel.

Speaker 1

But there's a trick for debugging.

Speaker 2

Yeah. Using structured exceptions to set a pseudoname helps identify threads in the debugger, and.

Speaker 1

Choosing between c plus plus plus standard library threats and the Windows API.

Speaker 2

Standard librarystd dot thread et cetera. Is cross platform, which is great, but the Windows API Create thread gives you much finer control over things like priority, affinity, stack size, which leads us to scheduling.

Speaker 1

Right, How does Windows decide which thread runs when the scheduler and.

Speaker 2

The key thing. Most threads are usually waiting, waiting for IO, waiting for a lock, et cetera. The scheduler focuses on threads in the ready state. It's priority based.

Speaker 1

Higher priority runs first. Windows has levels from real time down to idle.

Speaker 2

Correct. A thread's actual priority comes from its processes priority class plus its own relative priority within that.

Speaker 1

Process and the quantum the time slice.

Speaker 2

Yeah, how long a thread gets to run before the scheduler might switch. Yeah, It can vary client versus server tuning and the four ground apps. Threads often get longer quantums. Quantum stretching for responsiveness.

Speaker 1

Can be tweaked in the registry WIN thirty two priority separation.

Speaker 2

It can. Yeah. You can also control which ars a thread runs on process or affinity set thread affinity mask is the basic way set thread group affinity for systems with sixty four.

Speaker 1

Processors and CPU sets a newer way to group processor Yes.

Speaker 2

Windows ten introduce them more abstract way to manage affinity using functions like set thread.

Speaker 1

THEEP sets now priority boosts. This sounds important for keeping things smooth.

Speaker 2

Very the system temporarily boosts a threads priority after certain events like IO completing or a window needing. Attention prevents the UI freezing.

Speaker 1

It decays back down afterwards.

Speaker 2

Yes, after the thread runs for a bit four ground threads get a bigger boost when they wake up from a weight. It's all about perceived responsiveness.

Speaker 1

Suspending and resuming threads. Suspend thread, ReSm thread Still a bad idea.

Speaker 2

Generally, Yes, very easy to cause deadlocks. Better to use proper signaling. There are also ways for threads to yield voluntarily. Sleep baze gives up the rest of its time slice to another ready thread of the same priority.

Speaker 1

Switch to thread yields more aggestively yes to any.

Speaker 2

Other ready thread, and sleep infinite just waits forever until woken up.

Speaker 1

It's amazing how much orchestration is going on. Okay, synchronization within a process. Why do we need it?

Speaker 2

Because if multiple threads in the same process access shared data without coordination, chaos, race conditions, corrupted data, weird bugs.

Speaker 1

The simple counter example shows this clearly.

Speaker 2

Yeah, the final count is unpredictable for simple increments decrements, there are interlock operations.

Speaker 1

Like interlocked increment. These are atomic, yes.

Speaker 2

Hardware guaranteed atomic. The whole read, modify write happens as one indivisible step, save for simple updates.

Speaker 1

For more complex stuff, protecting blocks of code.

Speaker 2

Critical sections of the workhorse for that, within a process initialized critical section X, enter critical section to lock it, leave critical section to unlock. Only one thread can be inside the critical section at a time, and delete critical section when done.

Speaker 1

Mutual exclusion. The hashcatch example uses one to protect.

Speaker 2

A map exactly std dot unordered map isn't thread safe, so the critic section ensures safe access from multiple threads. The book also mentions ETW event tracing.

Speaker 1

For Windows for diagnostics.

Speaker 2

Yeah, powerful kernel level tracing can see image loads, context switches, tons of stuff, useful for deep analysis.

Speaker 1

Okay, what about SRW locks slim reader.

Speaker 2

Writer These are often more efficient if you have lots of threads reading share data but only occasional rights. They allow multiple readers or one writer acquires RW lock shared acquires our wots exclusive, et cetera.

Speaker 1

Got it and condition variables used.

Speaker 2

With a lock always with a critical section or an SRW lock. They let threads wait efficiently for some condition to become true. You call sleep condition variable CS or sleep condition variable SRW.

Speaker 1

This atomically releases the lock while waiting yes.

Speaker 2

And reacquires it upon waking. Other threads use weight condition variable or wake all condition variable to signal crucially, you must recheck the condition in a loop after waking because of spurious wakeups.

Speaker 1

Spurious wakeups, they can and wake up even if the condition isn't met sometimes.

Speaker 2

Yes, so you always loop while sleep condition variable. The producer consumer example demonstrates this pattern well with a shared queue right.

Speaker 3

Newer primitives, too, wait and address very efficient way to wait for a specific memory location to change value, often without needing a separate lock and synchronization barriers like a Runov point exactly enter synchronization barrier. Threads wait there until a specified number of threads arrive. Then they all proceed together and C.

Speaker 1

Plus plus standard library has its own versions std dot mutex std dot condition variable Yes.

Speaker 2

Good for cross platform code, but often less control or potentially different performance characteristics than the native Windows APIs. Finally, the basic weight functions wait for single object, wait for multiple.

Speaker 1

Objects, need the synchronize right for the object.

Speaker 2

Handle yes, and you specify a timeout. They tell you if the objects signaled, if you kimbed out, or if there was an error.

Speaker 1

Okay, that covers coordinating threads inside one process. What about between different processes?

Speaker 2

For that, you need kernel objects with system wide visibility, usually achieved using named.

Speaker 1

Objects like a named mutex.

Speaker 2

Exactly create it with create viewtex and give it a name, maybe global prefix for system wide. Another process can use open mutex with the same name to get a handle to the same mutex. Then they use weight for single object and release mutechs to coordinate.

Speaker 1

Process Explorer can show these named mutexes.

Speaker 2

Yep and whether they're currently held. Semaphors work similarly.

Speaker 1

Somemophors control access to a limited number of resources.

Speaker 2

Right create with create semaphore, give it an initial max account and a name. Wait for single object, tries to decrement the count, release semaphor increments it. Good for managing pools of resources across processes.

Speaker 1

Weaightable timers can also be named yes.

Speaker 2

Create weightable timer with a name, set weightable timer to schedule it once or periodically. Other processes can open weightable timer and wait for single object. Can even trigger APCs and events.

Speaker 1

Named events also possible.

Speaker 2

Create event with a name, manual or auto reset, open event by name, use set event, reset event, wait for single object. Simple signaling between processes.

Speaker 1

Interprocess APCs are less common.

Speaker 2

Much less common and trickier named objects the usual way. The book also mentions weight for impuddle.

Speaker 1

Waits for a GUI app to be ready.

Speaker 2

Yeah waits until it's finished initializing and is waiting for input. Useful after create process and signal object and weight atomically signals one object and weights on another, avoiding certain race conditions.

Speaker 1

Lots of tools for interprocess coordination. Let's move to thread pools, a managed way to handle threads.

Speaker 2

Yeah, Windows provides a sophisticated threadpool big advantages, reuses threads, less overhead, manages resources, better limits concurrency automatically.

Speaker 1

What do you use it? Simplest way?

Speaker 2

Try submit threadpool callback, give it a function to run, and the pool schedules it on one of its worker threads eventually.

Speaker 1

That it can do more weight callbacks yes.

Speaker 2

Instead of blocking your own thread waiting for an object, tell the thread pool to weight, create threadpool weight, set thread pool weight. When the object signals, the pool runs your callback function. Much more efficient. Timer callbacks too, yep, create threadpool timer, set thread pool timer schedule callbacks ceriodically or one shot handled by the.

Speaker 1

Pool and io callbacks rising operations.

Speaker 2

Right to create thread poolio start thread Polio integrates acinc iiocompletion with the threadpool.

Speaker 1

Can you create your own private pools?

Speaker 2

You can create threadpool allows customization minmax threads, stack sizes, set threadpool thread maximum, et cetera. Need to close thread pool when done.

Speaker 1

Callback environments, cleanup groups.

Speaker 2

More advanced features environments, TP callback environ let you set priority, affinity, etc. For callbacks. Clean up groups help manage the lifetime of related pool objects. Together.

Speaker 1

Thread pools seem very powerful, okay. Advance threading topics. Thread local storage TLS.

Speaker 2

G LS gives each thread its own private coffee of some data. Use to get an index, then tlset value, TELS get value, operate on the calling threads specific slot for that index. No sink needed because it's thread private. TLS free releases the index.

Speaker 1

C plus plus s thread local two Yes t lous.

Speaker 2

Pec thread older and thread locals entered. C plus plus provide language level support for static TLS variables.

Speaker 1

How do list threads again, tool help thirty two YEP.

Speaker 2

Create tool help thirty two snapshot with th h three two CSS snap thread then thread thirty two first next gives TIDPID priority, CPU times.

Speaker 1

Cash awareness, False.

Speaker 2

Sharing important performance consideration. False sharing is when threads modified different variables that happen to be in the same CPU cache line, causing unnecessary cash and validations. Padding data structures can help avoid it.

Speaker 1

Weight change reversal WCT for.

Speaker 2

Dead's locks yes an API open thread weightchain, session get thread weight chain to analyze what locks and objects threads are waiting on. Can help diagnose deadlocks by showing circular weights.

Speaker 1

And the concurrency run time. High level C plus plus library.

Speaker 2

For Microsoft Ya provides tasks parallel loops agents simplifies many common parallel programming patterns.

Speaker 1

Okay, nearly there. File and device io Create file and create file two are key absolutely fundamental for opening creating files, devices, pipes, tons of parameters, path access rights, read write, share mode creation disposition like creating new open existing flags and attributes.

Speaker 2

File flag overlapped is crucial for ACNC io.

Speaker 1

Yes, and paths can include for devices or things like symbolic links. Drive letters themselves are often similark.

Speaker 2

Getting file info size.

Speaker 1

Attributes, get file size x sixty four bit size, get file attributesx, get file information by handle for more details, set file information by handle. Can even modify some things reading.

Speaker 2

And writing read file, write file, sync or async both. ACNC requires the file flag overlapped flag during create file and using an overlap structure. APCs are one way to handle ACNC completion, but iocompletion ports IOCP are more scalable.

Speaker 1

IOCP involves create iocompletion port associating hands than worker threads, calling get cubed completion status.

Speaker 2

Exactly highly efficient for servers handling many concurrent acinc io operations. Threadpool io create thread poolio is a simpler wrapper around similar concepts.

Speaker 1

Canceling IO, conciliox yes, cancilo.

Speaker 2

X for ACNC cancel synchronusio exist but isn't guaranteed to work.

Speaker 1

Device io uses create file with device paths like physical drive YEP.

Speaker 2

Then device iiO control since commands directly to the driver using control codes.

Speaker 1

Finding devices, the set up DAPI right.

Speaker 2

Set of digit class, DEEVS setup dynam device info. Setup DIET Device interface detail lets you find devices by type and get their paths.

Speaker 1

Interprocess communication again pipes anonymous and named.

Speaker 2

Create pipe for simple parent child anonymous pipes, create name pipe for more powerful. Name pipes can be duplex workover network. Clients connect using create.

Speaker 1

File mail slots one way.

Speaker 2

Yes, connectionless, create mail slot for server, Create fil rite file for client Yeah less common now also file finding find first file etcter and system info.

Speaker 1

Get system info okay, last major topic. Memory management fundamentals Virtual memory.

Speaker 2

The big abstraction. Each process gets its own private address s base managed by the virtual memory and manager. VMM uses paging to swap memory between RAM and the disc page file.

Speaker 1

Memory states free, reserved, committed, free is unused.

Speaker 2

Reserved allocates address range but no storage. Committed allocates storage RAM or page file commit, charge and task Manager is the system wide total committed.

Speaker 1

Memory for a process commits size, private bytes is key, working set is RAM usage generally.

Speaker 2

Yes, virtual size includes reserved, working set is physical. RAM. Process Explorer shows these well.

Speaker 1

Process memory map shows layout code, DLL stack keep, Get process memory info, gives detailed stats.

Speaker 2

Page faults working set size, pool usage, page file usage, and page protection. Read write execute is critical set by virtual ALC, change by virtual protect access violation if you break.

Speaker 1

The rules virtual virtual query X lets you walk the address space.

Speaker 2

Yes, gives in memory based information about regions, base size, state protection type. Let's you see the map programmatically.

Speaker 1

And finally, WAWW sixty four for running thirty two bit apps on sixty four bit Windows file system redirection system thirty two versus siswell sixty four.

Speaker 2

Exactly the emulation layer that makes it mostly seamless. Wow sixty four disabled whole sixty four f's redirection can turn off the file redirection temporarily if needed.

Speaker 1

Wow. Okay, that was genuinely a deep dive. We covered so much ground.

Speaker 2

We really did, from processes as containers, threads as the workers, through handles, synchronization nightmares huh.

Speaker 1

And io memory basics.

Speaker 2

It's a lot, it is. You know, one thing that always strikes me is that PID thing just being a handle value and those minimal processes completely empty to start with. That's pretty wild.

Speaker 1

Yeah. And the whole dance of threads scheduling the boosts. It really helps understand why things feel responsive for sometimes why they don't and for you listening, even if you're not writing this kind of low level code. I think understanding these concepts gives you a much better feel for what your computer is actually doing under the hood.

Speaker 2

It definitely demystifies some of it takes away the magic feeling.

Speaker 1

So thinking about all this complexity. It's what makes Windows powerful, right, but it also feels like there are so many moving parts.

Speaker 2

Absolutely, it's this incredible layering of abstractions and mechanisms built up over decades. It enables amazing things. But yeah, complexity can also mean fragility.

Speaker 1

Sometimes it makes you wonder how does this foundation contribute to both stability and the occasional crash, And what other deep system areas might be interesting to explore next time, maybe digging into how memory actually gets allocated or how drivers work.

Speaker 2

Definitely food for thought, something to mull over until our next deep dive. Thanks for joining us.

Transcript source: Provided by creator in RSS feed: download file
For the best experience, listen in Metacast app for iOS or Android