@@CodeVault i have a question, if you pass "primes+i", then you would have primes[primes+i], is this expression correct? i mean shouldn't you also change in the function routine: primes[index]------>*(int*) arg or something like that
@@marco8673 no, u would just need to dereference the arg pointer (which is equal to primes+i), and this place in memory would contain the number you are looking for.
I am so happy to watch all these videos on this channel. He is genuinely one of the best teachers. I am really new to threads and c programming in general and he is making it so much easier on new programmers to learn. He starts with giving examples on how we would first think to approach an issue then tells us what is wrong with it and how we can improve it. I really like the way he teaches. thank you
Utterly hilarious video. I just ran into this exact situation six hours ago as I began to develop a test multi-threading program. After staring at the screen for two hours trying to figure out what was wrong, I solved it using a small const static array of values and used the loop index to index into the array and pass the address of the array element. KABOOM, problem solved. I did not need malloc() or free() because the small array was static in memory, trading off a little space for a little memory management processing. Great videos, absolutely tremendous. I'm so glad to have stumbled on your channel and have enjoyed several of your very informative videos. Thank you, thank you, thank you.
we can also pass value of a variable i by casting it as (void *) then in function we can again cast to int.. no need to allocate and deallocate for that. PS: you have the best OS coding videos, thanks! :)
I think that a remark on 12:16 "every single pointer has the same size" is a bit of a gaffe / misleading in the context of the free() call, because what we are actually freeing is a chunk of memory allocated by malloc. It's probably more relevant (and I guess valid in most cases) concerning the implicit conversion as we provide a (int *) as an argument to the pthread_create() which expects (void *).
Thank you for the video I definitely learn a lot from you. I think one important thing to mention too is that declaring the malloced int* also needs to happen inside the loop or else you you would pass the same pointer and free would free the value sometimes before other threads can use it. I had the same setup but assigned into an int of a struct and had double freeing issues because of this. Still trying how to figure out a way around this though while passing struct if there are any ideas I am all ears. :)
Yea, either allocate an array of int and pass a pointer to each of them or simply pass the value directly (and forcefully cast to pointer) if you only need to read it on the thread function
I dont understand why with this solutuion we wouldnt bump into the same problem, that is, when routine is sleeping but the for loop goes on, why doesnt the value of a get erased when we malloc it?
The value of a DOES get overwritten, that is correct. The difference is that we are no longer passing the address of a to the threads but we are passing a totally new part of memory that has been allocated with malloc to each thread. So, while, a itself may change, the value that was already passed to each thread doesn't. pthread_create(&th[i], NULL, &routine, &i); // here &i is always the EXACT same value (the address to the local variable i, which we know it changes in the for loop). Since we're passing the same value (which represents the address to i), whenever we change i in one thread (in the for loop for example) it changes for all the threads since they are all looking at the exact same part of memory. int* a = malloc(sizeof(int)); *a = i; pthread_create(&th[i], NULL, &routine, a); // here a is different for each iteration of the for loop. So on the next iteration, even though a itself changes, the value that we passed to each thread didn't (that value represents the address to which we stored the value of i for that thread)
First of all, THANK YOU very much for your recent playlists especially the UNIX ones. These lectures are very helpful and organized! I have a question which is unrelated to thread but arose from this example you showed. Inside the loop, instead of dynamically allocating new integers in each iteration, I just used ``int idx = i;'' hoping in each iteration a new int variable (idx) would be created from stack memory. Printing the address of this idx variable, I notice the addresses in each interactions are same, which indicates the idx variable is only created once and reused in all iterations. Is my understanding correct? It looks unintuitive though. I thought int idx = i; would declare and initiate new variables in each iteration.
It's correct for (i = 0; i < 10; i++) { int idx = i; } idx would only be defined once even though its initialization (to the value of i) will be executed multiple times. In fact, it does make sense. In 99% of the cases you only need one place to store the variable for all the iterations. It's really only this case that can cause issues. That is why we have dynamically allocated memory, to be able to control exactly when memory is allocated and deallocated. Basically any pair of { } inside a function defines only one set of each defined variable (regardless if it's a for loop, while loop or an if). But if you call that function multiple times those variables will get deallocated (when the function exits) and allocated again when the function starts executing again. I might make a video on this topic as it's quite interesting
When 'i' was declared inside the 'for' loop, why wasn't that giving an error on accessing its location after 1 sec as it would definitely have been out of scope(and deleted) in due course of time? It is instead giving a value of 10, does that mean it didn't get deleted on exit from the 'for' loop?
No. 'i' is a local variable to the main function. It gets deallocated only after the whole function finishes its execution (which is after the pthread_joins are called). So that 'i' remains allocated in memory. What you're talking about there is the visibility scope of that 'i' variable. It's defined in the for loop so I can't use it outside of that for loop, but its memory is located on that main function's stack
i have a question, if you pass "primes+i", then you would have primes[primes+i], is this expression correct? i mean shouldn't you also change in the function routine: primes[index]------>*(int*) arg or something like that
Yes, you could with semaphores. But frankly, it's redundant. Just use one thread instead to print them in order and don't worry about synchronization issues.
for(int i = 0; i < THREAD_NUM; i++) { if(pthread_create(&th[i], NULL, &dice, &i) != 0){ return i; } } In this case, when i is 9, and thread_create function is called during this, for loop is completed i is 10, now, i is local variable so, it is destroyed so, why index is printing 10? When not segmentation fault?
It's not destroyed if you are using pthread_join. The value is ten because the loop finishes execution before any of the threads have a chance to start executing
I understood what you meant, but I didn't understand how each thread sees the correct index just because it allocated a space in memory. Doesn't each thread, when it starts and enters the function, run the risk of accessing the same index? Why didn't you use the mutex in this case? Excuse my English, I'm using the translator
Not really, each thread gets created with a different input index therefore there is not issue accessing the same index. Actually, in this case it wouldn't even matter since we are only reading the values. Parallel reading of data is fine, only when writing do race conditions become a problem
or you can just pass : pthread_create(threads+i, NULL, display,(void *)(primes+i)); and since primes+i is a fixed address, once we passes it to our function we will never have a problem. i'm right ?
Yep, that's true for pointers. Another trick you can use if you want to pass a value (not a pointer) is: pthread_create(threads + i, NULL, &routine, (void*) 17); And, if you treat that arg in the routine function like an integer instead of a pointer, it will work just fine
Why not just pass the value like this: "&primes[i]"? Then in the routine function, typecase the void * to int * and dereference it like this: "printf("%d , *num)" to print it out? Is this a bad approach?
what if I create the routine function as void* routine(int arg) and pass i value? It works also. And you dont have to allocate dynamic memory. There is a downside?
No. That is also a solution. The only downside is that the API expects the function to be defined as void* routine(void* arg) and it might show you some warnings. Usually I keep the signature of the function as is and just cast arg to int
please could you explain how you would make the output print in order.. im asking because I am using what you have explained here to help me figure out how to approach my assigment.. for some reason my threads arent executing in order and I need to fix that. Thank you once again, your vids are a lifesaver
Well, threads are meant to NOT be executed in order. If you want to execute something in order, simply DON'T use threads. Now, if you absolutely want to use threads for this you could technically use a set of semaphores
Reas about preemption and atomic operations. You can't force them to work in order if it's multi threaded. To print in order, you could have them return values then have main print sequentially, or if it has to be printed in the threads, you would need some kind of semaphore to wait when done, have main wait until all are done, then release each semaphore in order BUT again you then need a signal that each thread has finished printing before you unlock the next.
If all you pass is an address to that i... That i can only have 1 unique value for ALL the threads it probably won't be 1 but it will be the value it exits from that for loop
pthread_join basically waits for the specified thread to finish execution. Without it, the main process might finish execution before all the threads finish and that would stop the threads that were still running
I used a static variable and a mutex and it actually worked. void *f(void *index) { pthread_mutex_lock(&mtx); static int i; printf(" Thread %d --> got number %d
", i, array[i]); i++; pthread_mutex_unlock(&mtx); return NULL; }
You could use semaphores or mutexes... Although, if you want them in order you could simply execute the print function in a for loop in the same thread (usually tasks like these are better suited for single-threaded applications)
I'm sorry about that. Getting quite a lot of questions every day. If you didn't get an answer right away try sending me a message. I'm trying my best to keep up with all the questions but there are a few here and there that I miss.
I've successfully done it by passing the thread array as an argument and using their ids: pthread_create(&th[i], NULL, &primeSelect, th); void* primeSelect(pthread_t* arg) { int i = 0; int match = 0; do { if(pthread_self() == arg[i]) match = 1; else i++; }while(!match) printf("%d ", primes[i]); }
We can pass address of position in array instead index "i", ie: "primes+i". I guess...
Yep, that's what I was looking for in an answer. Good job!
@@CodeVault Can we add a mutex on i ?
@@CodeVault i have a question, if you pass "primes+i",
then you would have primes[primes+i], is this expression correct?
i mean shouldn't you also change in the function routine:
primes[index]------>*(int*) arg or something like that
@@marco8673 no, u would just need to dereference the arg pointer (which is equal to primes+i), and this place in memory would contain the number you are looking for.
@@omeryacine8281 ok thank you!
I am so happy to watch all these videos on this channel. He is genuinely one of the best teachers. I am really new to threads and c programming in general and he is making it so much easier on new programmers to learn. He starts with giving examples on how we would first think to approach an issue then tells us what is wrong with it and how we can improve it. I really like the way he teaches. thank you
this man is a saint.
Man you are no less than God to me! You explain such complex concepts and debug stuff so easily, you are amazing.
You Indians would worship anything.
Utterly hilarious video. I just ran into this exact situation six hours ago as I began to develop a test multi-threading program. After staring at the screen for two hours trying to figure out what was wrong, I solved it using a small const static array of values and used the loop index to index into the array and pass the address of the array element.
KABOOM, problem solved.
I did not need malloc() or free() because the small array was static in memory, trading off a little space for a little memory management processing.
Great videos, absolutely tremendous. I'm so glad to have stumbled on your channel and have enjoyed several of your very informative videos.
Thank you, thank you, thank you.
You are my hero!
I just really appreciate all of your videos, very informative and easy to follow
we can also pass value of a variable i by casting it as (void *) then in function we can again cast to int.. no need to allocate and deallocate for that.
PS: you have the best OS coding videos, thanks! :)
Yeah, that's a trick you can use
I think that type of type punning violates strict aliasing and it can have problems with old arm processors because of alignment
that's what i looking for ty
Works like a charm :)
I think that a remark on 12:16 "every single pointer has the same size" is a bit of a gaffe / misleading in the context of the free() call, because what we are actually freeing is a chunk of memory allocated by malloc. It's probably more relevant (and I guess valid in most cases) concerning the implicit conversion as we provide a (int *) as an argument to the pthread_create() which expects (void *).
That conversion is what I was referring to there. Thanks for the feedback nonetheless!
fk, you are too good, I literally encounter the exact same problem of having duplicated value of i after passed to the thread function. You saved me
thanks for the lesson! better than my univeristy...
Excellent example and explanation. In pthread_create(), could you just pass in &primes[i] as the argument?
Exactly. That's the more simple answer
Thank you for the video I definitely learn a lot from you. I think one important thing to mention too is that declaring the malloced int* also needs to happen inside the loop or else you you would pass the same pointer and free would free the value sometimes before other threads can use it. I had the same setup but assigned into an int of a struct and had double freeing issues because of this. Still trying how to figure out a way around this though while passing struct if there are any ideas I am all ears. :)
Yea, either allocate an array of int and pass a pointer to each of them or simply pass the value directly (and forcefully cast to pointer) if you only need to read it on the thread function
Great video, thanks hugely. I was struggling with arguments in the pthread routine for a while
Very Nicely Explained.
Thanks a lot.
Wish you a happy new year ahead.
Happy new year!
apparently putting the sleep function after the pthread_create function works too lol thanx for your videos !!
literal saviour
extremely helpful explanation!
I dont understand why with this solutuion we wouldnt bump into the same problem, that is, when routine is sleeping but the for loop goes on, why doesnt the value of a get erased when we malloc it?
The value of a DOES get overwritten, that is correct. The difference is that we are no longer passing the address of a to the threads but we are passing a totally new part of memory that has been allocated with malloc to each thread. So, while, a itself may change, the value that was already passed to each thread doesn't.
pthread_create(&th[i], NULL, &routine, &i); // here &i is always the EXACT same value (the address to the local variable i, which we know it changes in the for loop). Since we're passing the same value (which represents the address to i), whenever we change i in one thread (in the for loop for example) it changes for all the threads since they are all looking at the exact same part of memory.
int* a = malloc(sizeof(int));
*a = i;
pthread_create(&th[i], NULL, &routine, a); // here a is different for each iteration of the for loop. So on the next iteration, even though a itself changes, the value that we passed to each thread didn't (that value represents the address to which we stored the value of i for that thread)
@@CodeVault Thanks a lot for your response! And thank you also for making quality content
First of all, THANK YOU very much for your recent playlists especially the UNIX ones. These lectures are very helpful and organized!
I have a question which is unrelated to thread but arose from this example you showed. Inside the loop, instead of dynamically allocating new integers in each iteration, I just used ``int idx = i;'' hoping in each iteration a new int variable (idx) would be created from stack memory. Printing the address of this idx variable, I notice the addresses in each interactions are same, which indicates the idx variable is only created once and reused in all iterations. Is my understanding correct? It looks unintuitive though. I thought int idx = i; would declare and initiate new variables in each iteration.
It's correct
for (i = 0; i < 10; i++) {
int idx = i;
}
idx would only be defined once even though its initialization (to the value of i) will be executed multiple times.
In fact, it does make sense. In 99% of the cases you only need one place to store the variable for all the iterations. It's really only this case that can cause issues. That is why we have dynamically allocated memory, to be able to control exactly when memory is allocated and deallocated.
Basically any pair of { } inside a function defines only one set of each defined variable (regardless if it's a for loop, while loop or an if). But if you call that function multiple times those variables will get deallocated (when the function exits) and allocated again when the function starts executing again.
I might make a video on this topic as it's quite interesting
@@CodeVault It makes sense. Thanks for your reply!
I wish you all the best.
When 'i' was declared inside the 'for' loop, why wasn't that giving an error on accessing its location after 1 sec as it would definitely have been out of scope(and deleted) in due course of time? It is instead giving a value of 10, does that mean it didn't get deleted on exit from the 'for' loop?
No. 'i' is a local variable to the main function. It gets deallocated only after the whole function finishes its execution (which is after the pthread_joins are called). So that 'i' remains allocated in memory.
What you're talking about there is the visibility scope of that 'i' variable. It's defined in the for loop so I can't use it outside of that for loop, but its memory is located on that main function's stack
Man you are a life saver!
i have a question, if you pass "primes+i",
then you would have primes[primes+i], is this expression correct?
i mean shouldn't you also change in the function routine:
primes[index]------>*(int*) arg or something like that
Yes, that's correct
can you make a video on how to pass multiple parameters using a thread. for example you want to pass an array and its size. how do we do it?
Sure! The idea is you just pass a struct for that. I'll make a video on it in the future
@@CodeVault yeah i just did that yesterday
@@CodeVault can you send a sample code?
how are two threads created at i=0 since the input to pthread_create is &th[i] so it must wait for the i value right
There is no intrinsic wait in the loop
I think that the simple solution is to create pointer of pointers that each thread will get the address of current index of the pointers array
That's an option as well. Depends what you want to do really. You could also pass the value itself, instead of a pointer
You are really great!!! Can you make IPC shared memory and message passing concept video?
Yea, they are on my list
Is there any way that we can see them in the order that they were in array?
Yes, you could with semaphores. But frankly, it's redundant. Just use one thread instead to print them in order and don't worry about synchronization issues.
for(int i = 0; i < THREAD_NUM; i++)
{
if(pthread_create(&th[i], NULL, &dice, &i) != 0){
return i;
}
}
In this case, when i is 9, and thread_create function is called during this, for loop is completed i is 10, now, i is local variable so, it is destroyed so, why index is printing 10?
When not segmentation fault?
It's not destroyed if you are using pthread_join. The value is ten because the loop finishes execution before any of the threads have a chance to start executing
I understood what you meant, but I didn't understand how each thread sees the correct index just because it allocated a space in memory. Doesn't each thread, when it starts and enters the function, run the risk of accessing the same index? Why didn't you use the mutex in this case?
Excuse my English, I'm using the translator
Not really, each thread gets created with a different input index therefore there is not issue accessing the same index. Actually, in this case it wouldn't even matter since we are only reading the values. Parallel reading of data is fine, only when writing do race conditions become a problem
or you can just pass :
pthread_create(threads+i, NULL, display,(void *)(primes+i));
and since primes+i is a fixed address, once we passes it to our function we will never have a problem. i'm right ?
Yep, that's true for pointers. Another trick you can use if you want to pass a value (not a pointer) is:
pthread_create(threads + i, NULL, &routine, (void*) 17);
And, if you treat that arg in the routine function like an integer instead of a pointer, it will work just fine
Why not just pass the value like this: "&primes[i]"? Then in the routine function, typecase the void * to int * and dereference it like this: "printf("%d
, *num)" to print it out? Is this a bad approach?
Yep, that's the better way of doing it
Your video is the best. thx so much
what if I create the routine function as void* routine(int arg) and pass i value? It works also. And you dont have to allocate dynamic memory. There is a downside?
No. That is also a solution. The only downside is that the API expects the function to be defined as void* routine(void* arg) and it might show you some warnings. Usually I keep the signature of the function as is and just cast arg to int
aren't function pointers smaller than "normal" pointers ?
Usually they are the same size
Could you do the same using mutex In the critical section
Yes, of course
please could you explain how you would make the output print in order.. im asking because I am using what you have explained here to help me figure out how to approach my assigment.. for some reason my threads arent executing in order and I need to fix that.
Thank you once again, your vids are a lifesaver
Well, threads are meant to NOT be executed in order. If you want to execute something in order, simply DON'T use threads.
Now, if you absolutely want to use threads for this you could technically use a set of semaphores
Reas about preemption and atomic operations. You can't force them to work in order if it's multi threaded. To print in order, you could have them return values then have main print sequentially, or if it has to be printed in the threads, you would need some kind of semaphore to wait when done, have main wait until all are done, then release each semaphore in order BUT again you then need a signal that each thread has finished printing before you unlock the next.
Thank you!
thanks for the help!
how we will get i value of same i=1 both threads please give some explanation about that.
If all you pass is an address to that i... That i can only have 1 unique value for ALL the threads it probably won't be 1 but it will be the value it exits from that for loop
You're a hero
I want to write a code in thread which reads the file how can do it?
Here's a video on how to read/write from files: code-vault.net/lesson/pt6uwax8pw:1603733523045
Can u simply pass &primes[i] ?
Yeah that should also work!
I just didnt understand why the numbers were not in order in the last output
That's because each thread prints out an element of the array and threads aren't guaranteed to execute in order
What is the use of pthread join
pthread_join basically waits for the specified thread to finish execution. Without it, the main process might finish execution before all the threads finish and that would stop the threads that were still running
I used a static variable and a mutex and it actually worked.
void *f(void *index)
{
pthread_mutex_lock(&mtx);
static int i;
printf("
Thread %d --> got number %d
", i, array[i]);
i++;
pthread_mutex_unlock(&mtx);
return NULL;
}
how to get the proper order output ?
You could use semaphores or mutexes... Although, if you want them in order you could simply execute the print function in a for loop in the same thread (usually tasks like these are better suited for single-threaded applications)
Very good videos on the youtube channel but too bad our concerns are being ignored on the discord server
I'm sorry about that. Getting quite a lot of questions every day. If you didn't get an answer right away try sending me a message. I'm trying my best to keep up with all the questions but there are a few here and there that I miss.
Also, please do note that I do not usually respond to questions I don't know the answer to and aren't related to any of the lessons posted.
can someone explain how to change the code to primes+I?
What do you want changed?
#include
#include
#include
#include
int primes[10] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
void* routine(void* arg) {
sleep(1);
int index = *(int*)arg;
printf("%d ",index);
// free(arg);
}
int main(int argc, char* argv[]) {
pthread_t th[10];
int i;
for (i = 0; i < 10; i++) {
//int* a = malloc(sizeof(int));
//*a = i;
if (pthread_create(&th[i], NULL, &routine, primes+i) != 0) {
perror("Failed to created thread");
}
}
for (i = 0; i < 10; i++) {
if (pthread_join(th[i], NULL) != 0) {
perror("Failed to join thread");
}
}
return 0;
}
best content
I've successfully done it by passing the thread array as an argument and using their ids:
pthread_create(&th[i], NULL, &primeSelect, th);
void* primeSelect(pthread_t* arg)
{
int i = 0;
int match = 0;
do
{
if(pthread_self() == arg[i]) match = 1;
else i++;
}while(!match)
printf("%d
", primes[i]);
}
That's a very creative idea. Very nice, good job!
understood
i love you so much
You can support the channel over on: code-vault.net/support-us
My implementation:
#include
#include
#include
int j = 0;
int primes[] = {2, 3, 5, 7, 11, 13, 17, 19 ,23, 29};
pthread_mutex_t mutex;
void* routine(){
int* res = malloc(sizeof(int));
pthread_mutex_lock(&mutex);
*res = primes[j++];
pthread_mutex_unlock(&mutex);
return (void*) res;
}
int main(int argc, char const *argv[])
{
pthread_t threads[10];
pthread_mutex_init(&mutex, NULL);
for(int i = 0; i < 10; i++){
pthread_create(&threads[i], NULL, &routine, NULL);
printf("Thread %d has started
", i);
}
for(int i = 0; i < 10; i++){
int *res;
pthread_join(threads[i], (void **) &res);
printf("Running of thread is finished returning %d
", *res);
free(res);
}
pthread_mutex_destroy(&mutex);
return 0;
}
That's also a nice solution. The only problem is that now, you can't fully run all the threads in parallel due to the mutex