1 00:00:00,000 --> 00:00:07,066 [No Audio] 2 00:00:07,067 --> 00:00:09,366 Scoped threads is a relatively new feature 3 00:00:09,367 --> 00:00:13,500 that is being added to Rust 1.63.0. It 4 00:00:13,501 --> 00:00:15,900 allows the threads to borrow local variables 5 00:00:15,901 --> 00:00:18,766 with lifetimes more effectively. The problem 6 00:00:18,767 --> 00:00:21,100 with threads is that when using threads, we 7 00:00:21,101 --> 00:00:23,300 don't know exactly when the closure we give 8 00:00:23,301 --> 00:00:25,766 to threads spawn will run or execute, 9 00:00:26,366 --> 00:00:28,400 meaning it is hard to determine when 10 00:00:28,433 --> 00:00:30,300 variables borrowed by threads will be 11 00:00:30,301 --> 00:00:32,900 dropped. Let us look at an example to explain 12 00:00:32,901 --> 00:00:35,566 this. I will bring the relevant modules into scope. 13 00:00:35,567 --> 00:00:41,666 [No Audio] 14 00:00:41,667 --> 00:00:43,400 Next, I will define a vector. 15 00:00:43,401 --> 00:00:47,500 [No Audio] 16 00:00:47,501 --> 00:00:50,266 I will also define a variable containing some value. 17 00:00:50,267 --> 00:00:54,433 [No Audio] 18 00:00:54,434 --> 00:00:57,066 The scope function in the thread module allows us 19 00:00:57,067 --> 00:00:59,033 to define a scope in which we can spawn 20 00:00:59,034 --> 00:01:02,100 threads. All the threads that resides inside 21 00:01:02,101 --> 00:01:03,966 a scope will remain in that scope and will 22 00:01:03,967 --> 00:01:06,466 complete its execution in this scope. So let 23 00:01:06,467 --> 00:01:08,266 us create a thread scope. 24 00:01:08,267 --> 00:01:11,862 [No Audio] 25 00:01:11,863 --> 00:01:13,600 We can now spawn some threads 26 00:01:13,601 --> 00:01:15,000 inside this scope using the 27 00:01:15,001 --> 00:01:18,100 spawn function on the variables of some_scope. 28 00:01:18,101 --> 00:01:23,033 [No Audio] 29 00:01:23,034 --> 00:01:25,133 I will include a simple print statement to 30 00:01:25,134 --> 00:01:26,266 the body of the thread. 31 00:01:26,267 --> 00:01:30,700 [No Audio] 32 00:01:30,701 --> 00:01:32,933 I can access the variable of vec inside the 33 00:01:32,934 --> 00:01:35,866 thread now, I will access it inside a print statement. 34 00:01:35,867 --> 00:01:41,533 [No Audio] 35 00:01:41,534 --> 00:01:43,933 You may note that the compiler has no issues. 36 00:01:44,266 --> 00:01:46,833 Although we have not moved the ownership of 37 00:01:46,834 --> 00:01:48,900 the variable inside the thread, and the thread 38 00:01:48,901 --> 00:01:51,533 do not own the variable. This is because 39 00:01:51,534 --> 00:01:53,466 there is no confusion with regards to the 40 00:01:53,467 --> 00:01:55,833 lifetime of the variable vec in this case. 41 00:01:56,233 --> 00:01:58,300 The thread scope enforces the threads to 42 00:01:58,301 --> 00:02:01,166 complete within this scope, and this 43 00:02:01,167 --> 00:02:03,533 ensures that this thread will complete before 44 00:02:03,534 --> 00:02:05,933 the end of the main thread. Since the 45 00:02:05,934 --> 00:02:07,933 variable defined in the main has the scope 46 00:02:07,966 --> 00:02:10,032 equal to the main function, therefore the 47 00:02:10,033 --> 00:02:12,566 variable of vec will remain in scope when 48 00:02:12,567 --> 00:02:15,300 the thread executes. The thread is not 49 00:02:15,301 --> 00:02:17,266 allowed to live beyond the scope in which it 50 00:02:17,267 --> 00:02:21,000 is defined in this case. Let us also define another thread. 51 00:02:21,001 --> 00:02:25,966 [No Audio] 52 00:02:25,967 --> 00:02:28,633 I will add a simple print statement to the body. 53 00:02:28,634 --> 00:02:32,866 [No Audio] 54 00:02:32,867 --> 00:02:35,233 Let us mutably access the variable x 55 00:02:35,234 --> 00:02:38,066 in this thread and update its value. You may 56 00:02:38,067 --> 00:02:41,133 note that the compiler has no issues. Outside 57 00:02:41,134 --> 00:02:43,500 the scope, I will add a simple print statement. 58 00:02:43,501 --> 00:02:49,300 [No Audio] 59 00:02:49,301 --> 00:02:51,566 This print statement will only execute when 60 00:02:51,567 --> 00:02:54,433 the scope ends. Since the threads are inside 61 00:02:54,434 --> 00:02:56,333 the scope, so it means that this line will 62 00:02:56,366 --> 00:02:58,966 only execute once both the threads are done 63 00:02:58,967 --> 00:03:01,400 with their execution. When the threads are 64 00:03:01,401 --> 00:03:03,566 done, the variables will be available with 65 00:03:03,567 --> 00:03:06,133 the main and now it can be used. So, let me 66 00:03:06,134 --> 00:03:07,566 access the two variables. 67 00:03:07,906 --> 00:03:11,011 I will add an element to the vector. 68 00:03:11,012 --> 00:03:18,266 [No Audio] 69 00:03:18,267 --> 00:03:20,666 Finally, I will print the two values inside 70 00:03:20,667 --> 00:03:22,433 the print statement. 71 00:03:22,434 --> 00:03:26,165 [No Audio] 72 00:03:26,166 --> 00:03:27,700 Let us execute the code now. 73 00:03:27,701 --> 00:03:31,000 [No Audio] 74 00:03:31,001 --> 00:03:33,266 You may note that it is working fine. In 75 00:03:33,267 --> 00:03:35,600 summary, the thread scope is creating a scope 76 00:03:35,601 --> 00:03:38,166 in which we can spawn new threads. Those 77 00:03:38,167 --> 00:03:40,366 threads are automatically being joined at the 78 00:03:40,367 --> 00:03:42,600 end of the scope. When all the threads have 79 00:03:42,601 --> 00:03:45,166 completed, then the entire block completes, and 80 00:03:45,167 --> 00:03:47,833 therefore the scope also completes, and then 81 00:03:47,834 --> 00:03:50,700 we continue with our remaining program. The 82 00:03:50,701 --> 00:03:52,500 regular ownership rules related to the 83 00:03:52,501 --> 00:03:55,000 mutability are observed inside a certain 84 00:03:55,001 --> 00:03:57,833 scope, that is we can have only one mutable 85 00:03:57,834 --> 00:04:00,200 reference in scope. We can have multiple 86 00:04:00,233 --> 00:04:03,100 immutable references in scope and mutable and 87 00:04:03,101 --> 00:04:05,900 immutable reference cannot coexist inside the 88 00:04:05,901 --> 00:04:08,433 scope. Let us see some details of these 89 00:04:08,434 --> 00:04:11,366 rules in an example. If we push an element 90 00:04:11,367 --> 00:04:13,833 in the second spawn thread to the vec, then it 91 00:04:13,834 --> 00:04:15,500 will give out an error message. 92 00:04:15,501 --> 00:04:19,666 [No Audio] 93 00:04:19,667 --> 00:04:22,033 You may recall from the section where we explained 94 00:04:22,034 --> 00:04:24,366 the closures, that the closures will try to 95 00:04:24,367 --> 00:04:26,800 infer based on the usage of the variable, how 96 00:04:26,801 --> 00:04:28,900 the variables are going to be borrowed inside 97 00:04:28,901 --> 00:04:31,100 the closure. If the variables are not being 98 00:04:31,101 --> 00:04:33,333 mentioned explicitly in the list of arguments 99 00:04:33,334 --> 00:04:35,600 to the closure. In the closure of the first 100 00:04:35,601 --> 00:04:37,733 thread, the variable vec is being borrowed 101 00:04:37,734 --> 00:04:40,033 as immutable. And now in the closure of the 102 00:04:40,034 --> 00:04:42,266 second thread, we are trying to borrow 103 00:04:42,267 --> 00:04:45,400 it mutably. Since mutable and immutable cannot 104 00:04:45,401 --> 00:04:47,100 coexist in a scope, therefore the Rust 105 00:04:47,101 --> 00:04:50,066 compiler complains. We can have many 106 00:04:50,067 --> 00:04:52,566 immutable references in a scope. For instance, 107 00:04:52,600 --> 00:04:54,433 I can access the vec in the second thread 108 00:04:54,466 --> 00:04:56,266 also, without having any issues. 109 00:04:56,267 --> 00:05:01,166 [No Audio] 110 00:05:01,167 --> 00:05:03,100 Now let us see what would happen 111 00:05:03,185 --> 00:05:04,966 if we do not use the 112 00:05:04,967 --> 00:05:08,033 scope, but rather use simple threads not in a 113 00:05:08,034 --> 00:05:10,933 certain scope. I will use the simple thread 114 00:05:10,934 --> 00:05:13,333 spawn function for creating the new threads. 115 00:05:13,733 --> 00:05:16,266 First I will comment out the thread scope and 116 00:05:16,300 --> 00:05:18,333 the second line, where I use the scope to 117 00:05:18,334 --> 00:05:19,866 spawn the threads. 118 00:05:19,867 --> 00:05:22,233 [No Audio] 119 00:05:22,234 --> 00:05:24,166 I will use simple thread function. 120 00:05:24,167 --> 00:05:27,866 [No Audio] 121 00:05:27,867 --> 00:05:29,833 Next, I will also comment out the 122 00:05:29,834 --> 00:05:32,418 scope based spawning of the second thread, 123 00:05:32,419 --> 00:05:34,318 and we'll use simple code for spawning it. 124 00:05:34,319 --> 00:05:40,200 [No Audio] 125 00:05:40,201 --> 00:05:42,033 You may note that the compiler is complaining 126 00:05:42,034 --> 00:05:44,266 in this case. Let us see the errors in this 127 00:05:44,267 --> 00:05:46,733 case. It says closures may outlive the 128 00:05:46,734 --> 00:05:49,200 current function, but it borrows vec, which is 129 00:05:49,233 --> 00:05:52,066 owned by the current function and may outlive 130 00:05:52,100 --> 00:05:55,233 the borrowed value. What this is saying 131 00:05:55,234 --> 00:05:57,100 effectively is that, the closure is going to 132 00:05:57,101 --> 00:05:59,700 live longer, than the variable vec is 133 00:05:59,701 --> 00:06:01,966 potentially going to. Because the closure 134 00:06:01,967 --> 00:06:04,200 doesn't have ownership over the variable vec, 135 00:06:04,201 --> 00:06:06,700 so it doesn't have any control over how long 136 00:06:06,701 --> 00:06:10,466 it lives. So what might happen in this setup 137 00:06:10,467 --> 00:06:13,266 is that, this thread might spawn and then the 138 00:06:13,267 --> 00:06:16,066 main may take up turn and goes to completion 139 00:06:16,067 --> 00:06:17,900 thereby dropping the variable of vec. 140 00:06:18,166 --> 00:06:21,300 Because this function no longer needs it, if 141 00:06:21,301 --> 00:06:23,666 it happens before this thread has finished, 142 00:06:23,700 --> 00:06:26,166 which can happen in this scenario with this 143 00:06:26,167 --> 00:06:27,966 version of the thread, then the thread may 144 00:06:27,967 --> 00:06:31,500 not be able to do its job correctly. One way 145 00:06:31,501 --> 00:06:33,933 to fix this is to use the move keyword before 146 00:06:33,934 --> 00:06:36,300 the closure. But with the move, we are not 147 00:06:36,301 --> 00:06:39,166 being able to use the variables afterwards, as 148 00:06:39,167 --> 00:06:41,866 it moves the ownership into the closure. Of 149 00:06:41,867 --> 00:06:44,166 course there are other fixes also, but each 150 00:06:44,167 --> 00:06:46,833 comes with its own limitations. The scope 151 00:06:46,834 --> 00:06:48,533 represents a nice solution where the 152 00:06:48,534 --> 00:06:51,033 variables are either reference immutably or 153 00:06:51,034 --> 00:06:53,233 immutably, and the ownership remains with the 154 00:06:53,234 --> 00:06:55,733 main program. That brings us to the end of 155 00:06:55,734 --> 00:06:57,766 this tutorial. I hope you would have enjoyed 156 00:06:57,767 --> 00:07:00,233 this. See you again and until next tutorial 157 00:07:00,234 --> 00:07:01,666 happy Rust programming. 158 00:07:01,667 --> 00:07:07,166 [No Audio]