What are Race Conditions?
HTML-код
- Опубликовано: 7 июн 2024
- Source code can be found here:
code-vault.net/lesson/18ec194...
===== Support us through our store =====
code-vault.net/shop
===== Check out our website =====
code-vault.net
===== Check out our Discord server =====
discord.code-vault.net
Never seen race conditions broken down pragmatically like this in my life. I was awestruck when you took it to the assembly level. I couldn't believe my eyes. Thanks for this great video boss.
this is pure preciosity
The OS subject should be taught like this, instead of whiteboarding.
This is to the point. Thanks!
you just don't pay attention to your teacher, give them some credit
@@jardondiego whiteboarding is full of abstractions, this is showing verything under the hood, so more powerful for learning
I get so happy when I search up an OS topic and your video pops up because I know for a fact Ill understand it. Amazing work man!!
Thanks for putting efforts for all of us! really love your content, to the point yet detailed.
4:13 you nailed it. This core explanation is what most of the tutorials are missing.
First time getting in contact with threads, you make the concept so easy to understand. Thanks a lot for the content!
As somebody who is just at the beginner level of C I can say, you produce the most "family friendly" (all the "horrors" of C compiled into nice, easy to follow explanations) videos on C. Well done!
C imo is the least "horror" inducing language out there
C# and Java has a whole "horror" procedure just to write to console.
Ofc, if you get into obfsucated C, it will get bad visually
Those from 42 Network, give it a like and good luck with the philosophers project! 🙏
Thank you very much for all of your videos about processes and threads
if professors could explain like you everyone would pass
I don't really think so. Some people don't even go to all their classes.
@@kayakMike1000 Those are either the people that end up passing with the highest grades or the slackers that wont make it through. There is no in between for people who dont go to class. At least in modern times. Back when teachers actually taught and didnt just play a youtube video in class as a form of "teaching", good students would actually attend all classes. But times have changed. For the worse, if you ask me. Now spending your time learning on your own is the best way to go, sometimes even the only way to go.
Wow, impressive clear and really fast to understand the concept. Thank you!
Thread-safe-ness is a really important topic :) amazing explanation - enjoyed it, even though i already knew about it. never seen it in assembly though. loved that part, helps understanding the whole picture if you're not into it.
Your classes are amazing! All of them! Just one thing, I think that when you say race condition, the correct term is data race. Cheers!
thank you very much, it was amazing to see how the assembly do things
That's a very eye opening presentation my master. You're hundred times better at teaching than my professor. I very appreciate of all the work you made. Thank you so much master. 😘😘
Dude, this is great stuff! Excellent explanation skills
Nice to see you back !
Beautifully explained!
Thx for video and please keep thread video series very detailed because on youtube there's no detailed playlist, please go into deep, my friend. And thank you sooo much. Keep it up 😃
There's a lot to cover (condition variables, barriers, producer-consumer problem etc. + examples/exercises) so expect at least ~20 videos on the topic. If you have anything specific in mind please tell me!
@@CodeVault you're breathtaking! Thank you so much 😘
you are amazing bro! Big brain + good teacher. No words, how this is free
It's also important to note the case when each thread reads the same value from memory, increments it and writes it back to memory, effectively "removing" one of the thread operations. I think this is more likely to happen than one thread being allowed to run multiple times before allowing the next to run and undo the work of the first thread
Very clear explanation and a great course in total!
Ahahhaha he's so funny! It's charming to watch your videos. You have a very awesome vibe!
Outstanding explanation mate
this video is so clear and well explained . thank you !
Thanks for the amazing explanation. @ 11:35, you said one thread would be executed first, after which the second thread would be executed. But in the first video of this series, you said that threads are implemented in parallel and not one after the other. You even demonstrated this using sleep(3). Please clarify.
Basically in the time it takes to create the next thread, the first thread finishes its execution. While it's true that threads run in parallel, the first threads that are created get a head-start
Thank you man this was really helpfull you are a great!
You are Genius, i am cannot speak english very well but i want to say to you very very very thank you about this amazing explanation
what a beautiful simply put explanation!
Great video! Thanks for the great explanation. I mainly use Python but this was very similar
Definitely. The threads tutorial could be used in any language as long as you can translate the higher level concepts like thread, mutex, barrier etc.
Hey,
First thing thank you very much for your Videos, could you name the IDE, which do you use ? and on which Operating system do you work ?
Ich hope of an answer :)
I'm using Visual Studio Code that is remotely connected to a Debian machine. The videos are recorded on Windows
Can I say race condition is more likely to occur when setting loop to 1 million because it takes longer time to finish the execution for each threads? In other words, thread p2 will be created after thread p1. But it is up to OS scheduler to decide which thread to run and how long it will run for one scheduling time slot. So if the execution time is very long and need more than just one scheduling slots, it is much easier to threads to interleave with each other. Is my understanding correct? Anyway, thanks for your great explanation in the video!
Yea, that is true. Similarly, if you have threads that execute in a short amount of time, race conditions occur less often. Also, if the instruction(s) are finished in one CPU cycle there's no way for race conditions to occur. This is the reason why semaphores don't create race conditions when you call sem_wait and sem_post
Awesome stuff! One thing I don't get is how each thread's register would hold on to the value it originally read in a single CPU. If both threads are run on separate CPUs then it makes sense, but if they are both on the same CPU then surely the other thread will overwrite eax with its own value unless there are additional instructions to push the original value to another register or to memory to save it? Does the kernel do this automatically when it tells the thread to 'take a break'? :)
Yes, the kernel does it automatically with something called "context switching". Basically all threads/processes get some CPU time if they are running at the same time. So instead of your while(true) loop blocking the whole computer (assuming you have 1 core and 1 CPU) it would allocate some execution time to that process and then context switch to another process that needs to execute and so on and so forth.
I could be wrong, however a thread shares the same memory from the main. Except the program counter, stack and its own set of registers. Therefore it seems that its writing to the same register, however a different set of registers which loads between context switching of threads/processes.
Thank you a lot for the video! Great as always :) Could you please explain why there is the same number (23) at "read mails" and "increment" steps? I assumed the incrementation step result is 24 as well as the "write" step
Ahh, that is because this mail++ operation we do has multiple steps in the CPU itself:
1) Read the "mail" value from memory to the CPU register
2) Increment the value stored in that CPU register
3) Write whatever is in that CPU register to the address where "mail" is stored
What I am showing in that diagram is always the actual value of "mail" in the memory (not in the CPU), hence why it's still 23 in the increment row
My only doubt is if in the cpu register is 30 in the increment phase, so it should increments and turn in 31. How is 30 in the cpu register and you increment to 24?
By the way, thanks a lot for all your videos!! And I miss new videos. You are the best!
Stunning explanation!
thank you so much brother ❤
as i heard from you that with threading that threads should go in parallel, as you show in a previous video example. Isnt race condition breaking the parallel thing here? very nice explanation
They don't always have to go in parallel. Yes, ideally is to have threads that always work in parallel but sometimes you need to prevent situations like these from happening.
Around 8:10 time, if for T2, the increment (register) value in the CPU is 30, then shouldn't it work with that register value and write 31 to the memory? How will it increment 23 to 24, if the register value has been 30?
I also googled and each thread will have its own register and stack, so T2 will not have 30. Any thoughts?
That diagram I showed seems to be confusing. Should've done a better job but, what is in each cell is actually the value that is inside the variable at the point of execution (not necessarily what each thread sees). I hope that clears up the confusion
You should be extremely proud of yourself. You explained it beautifully.
It occurs to me race conditions could be used to generate truly random numbers, something like:
void* rng_thread( void *ud )
{
while ( 1 )
{
rng_seed++;
pthread_yield();
}
}
The pthread_yield() is just there to give the system a chance to kill the app &/or thread
They won't truly be random but they are probably going to depend a lot on the environment it's running on (for example what other processes are running and whatnot)
@@CodeVault Compared to pseudo random numbers generated by say the LSR somethinf method (forgot the name) it is definetly less predictable, although this method is likely only of use in games where some things should be harder to predict, like enemy actions
This reminds of that lava lamp wall that is recorded by a camera which is used to generate random numbers. Usually pseudo-random numbers are good enough but, if you ever need a truly random number, I guess using something from real life and encoding it into a number is probably the closest we can get to true randomness
You need to make that global variable volatile and make sure your compiler doesn't optimize your loop.
@codeVault Hello sir could you justify this statement. If threads run parallely then for the mail variable gets incremented by the two threads at the same time.
So the net increase in the count should be 1. As both the threads increment the mails variable at same time.
Yes. Basically both threads read the same number (say, 45) and they both individually increment this number by 1 to 46. Then, they both write to that place in memory that 46. So even though 2 increments happened, we can only see one
this is amazing :)
wow, what a lesson, thank you so much
Fantastic video totally understand now
in your example at 8:20 the increment for t2 is 30. Doesn't it have to be 23, because each Thread calls the routine function at the start, which means that they both create a new function call which is put on the stack? So the iteration of the for loop is in both threads 1000000 times or am I wrong? The problem is that for example thread 2 and thread 1 manipulate the variable mails at the same time which can cause the shown problems. So my question is, does each thread iterates the for loop exactly 1000000 times in your example.
Yes, each thread loops exactly 1000000 times.
I guess that explanation was a bit wrong as the value should represent what each thread has read, not what the actual value is in variable. I should've put 23 there instead of 30, you're right.
@@CodeVault thank you very much :) your videos are the best they helped me a lot!
@CodeVault :
@10:18 : line 26, ;at line of the L2 command : add1 $1, -4(%rbp)
This add 1 to the memory address of (rbp - 4)
-> What is the point of this ?
Thanks in advance.
That's just incrementing the i variable (from the for loop). Notice at the top how -4(%rbp) is initialized with 0 and at the bottom how it is compared with our number of iterations
You explain soooo well
Thank you! clearly explained
according to your code there are 2 pthreads, with small numbers in mail variable increment both the thread excecuted sequentially (first thread 1 and after that thread 2). when you increased mail increment to 1000000 does thread one and thread 2 excecutes concurrently ? if they excecute concurrently, will this concurrent excecution will occur on single core cpu's ? or this concurrent excucution will happen only on cpu's with dual or more cores ? anyone please explain
The concurrent execution can happen on both single core and multi core CPUs. Operating systems use something called "context switching" (you can google the term to find out more). Basically it's how multiple processes run simultaneously in an OS even with single core CPUs
@@CodeVault thank you brother
Thank you so much!
What if I'm working with threads and I get an unexpected value just like in the mailbox example. How can I tell if the result is due to a race condition or to an overflow ?
That's the issue with race conditions. It's difficult to tell when they happen. For overflows you could maybe check for upper or lower bounds. For race conditions... I'm not aware of any way you can detect them (maybe with a checksum of sorts?)
overflow will give excact same result within excact same input
race conditions are much chaoticalier and`ll result different output each time
How did you open assembly page? I can't open it.
The shortcut I used there is CTRL + P (although you should also find the main.s file near your main.c file in the same folder)
@@CodeVault Yes! I found .s file near it! Thank you!
8:45 I didn't understand the issue. For all the time the value of global variable stays the same if it looks in the memory. Then why did it change, from 30 to 24?
Sorry.. understood, didn't listen the word register.
@@iloveukraine-subscribe1kgo822 Didn't register? Sorry... somebody had to do it... ;)
Doing Wonderful Job ...that to for free. Service to humanity, sure you will be suitably rewarded.
A absolute king.
congrats!
Why didn’t we created separate routine for both the threads and added a sleep in one thread to simulate one thread occupied while other is executing longer
Agree that race condition is not guaranteed but the probability will increase right?
I think it might decrease since the overlap of execution time will be smaller
A 100 iterations didnt work because C compiler optimization turns loops where there is only one number incremented a couple times into "non loops", so a loop where x is inc. 10 times will be turned into x += 10 by the compiler. Thats why there were no race conditions with small numbers. Not because it takes too long or too short or smth ... .This optimisation stops at a certain number.
Ahh, that makes sense. Should've looked at the assembly code more carefully then. Thanks for clarifying!
Just incase you forgot, you are the GOAT!!
I feel the frustration when race condition did not occur despite of increasing the value to 10000
The CPUs are too fast these days haha
Let me guess... you were also surprised you had to go up till million to create the race condition :D I honestly expected it much sooner! I don't know if its C being good at this or what but I arrived at race conditions in other languages way sooner. I guess afterall it involved "luck" tho a little. You could even see 1 instead of 2 without a loop?
Commented it too soon. You explained it in the end. Amazing!
but the pthread_exit() is important ? or not?
Not really. It's optional. pthread_exit is called automatically when you return anything from the thread function
@@CodeVault thank you, hero
understood
2 words. Thank you.
jesus!
I love you!
Dude, you could give a simpler to understand explanation for noobs:
Think of each thread as a person, they each copy information from a document, they then modify that information and overwrite the old information, each person starts at different times but over time their timings align such that when one person copies information it is before the other person has updated the information with their own modified state meaning the information they modify is out of date and will cause the other person to get older information after they overwrite the documents information, the timing of the overwrites is the race condition
Yea, that's a great example! Thanks for the feedback. I'll try to use this example from now on for race conditions
sir one video create on setup phtread in vs code
Add "-pthread" to your build.json args list and it should compile without issues if you're on a Unix system
@@CodeVault i am in Window
@@ReactCode0 pthreads are unix-only. You could try running WSL with Ubuntu and compile and run your project there
@@CodeVault thanks sir
something to do with "white privilege" and colonialism?
No. It's about issues regarding multiple threads accessing (and modifying) the same address in the computer memory
@@CodeVault Well then, it sounds like something that would be good to know!