1 00:00:00,000 --> 00:00:06,266 [No Audio] 2 00:00:06,267 --> 00:00:08,610 In this video, we are going to learn about how 3 00:00:08,611 --> 00:00:10,530 to handle data that is shared between 4 00:00:10,531 --> 00:00:13,050 multiple threads. This is very important 5 00:00:13,051 --> 00:00:15,450 topic in the context of concurrency. Since the 6 00:00:15,451 --> 00:00:17,700 threads can execute concurrently, therefore, 7 00:00:17,730 --> 00:00:20,100 we need to be careful while passing the data 8 00:00:20,101 --> 00:00:22,650 between the threads to ensure that the reads, 9 00:00:22,651 --> 00:00:25,380 and updation to the data is always done in 10 00:00:25,381 --> 00:00:28,290 the right way. So let's get started. The 11 00:00:28,291 --> 00:00:30,480 mechanism which is used for handling, 12 00:00:30,481 --> 00:00:32,910 transferring, or using shared data between 13 00:00:32,911 --> 00:00:35,100 multiple threads is called message passing. 14 00:00:35,580 --> 00:00:38,340 The Rust achieves message passing using the 15 00:00:38,341 --> 00:00:40,740 tool called a channel, which is included in 16 00:00:40,741 --> 00:00:43,140 the standard library. The concept of channel 17 00:00:43,141 --> 00:00:45,390 is fairly simple, and it may be understood 18 00:00:45,391 --> 00:00:48,510 using the analogy of a water stream like a 19 00:00:48,660 --> 00:00:51,810 river or a water stream. If you put something 20 00:00:51,840 --> 00:00:54,450 like a boat or some other physical item on 21 00:00:54,451 --> 00:00:56,880 the stream, it will travel down the stream to 22 00:00:56,881 --> 00:00:59,580 the end of the waterway. A channel in 23 00:00:59,581 --> 00:01:02,010 programming has two halves the transmitter 24 00:01:02,011 --> 00:01:04,379 and the receiver. Going back to the river 25 00:01:04,380 --> 00:01:06,510 analogy, the transmitter is the upstream 26 00:01:06,511 --> 00:01:09,000 location where you would place the boat or 27 00:01:09,001 --> 00:01:10,920 some other physical item that you want to 28 00:01:10,921 --> 00:01:13,380 transmit to the other end, and the receiver is 29 00:01:13,381 --> 00:01:15,390 the downstream location, where the boat will 30 00:01:15,391 --> 00:01:19,410 end up and will be properly received. One 31 00:01:19,411 --> 00:01:21,450 part of your code calls methods on the 32 00:01:21,451 --> 00:01:24,150 transmitter passing, passing in the data you 33 00:01:24,151 --> 00:01:26,550 want to send, and another part of your code is 34 00:01:26,551 --> 00:01:28,410 listening to the receiver for arriving 35 00:01:28,411 --> 00:01:31,050 messages. The channel is set to be closed if 36 00:01:31,080 --> 00:01:33,210 either the transmitter or the receiver have 37 00:01:33,240 --> 00:01:36,000 is dropped. From programming perspective, the 38 00:01:36,001 --> 00:01:38,850 channels are like queue which follows the first 39 00:01:38,851 --> 00:01:41,970 in first out order. That is the item or data 40 00:01:41,971 --> 00:01:43,920 which is being inserted first will be the 41 00:01:43,921 --> 00:01:46,320 first one which goes out of the queue, the 42 00:01:46,321 --> 00:01:48,540 sender or transmitter will push items into 43 00:01:48,541 --> 00:01:50,880 the queue and the receiver will read the 44 00:01:50,881 --> 00:01:52,800 items from the queue in the same order in 45 00:01:52,801 --> 00:01:54,870 which they are being inserted into the queue. 46 00:01:55,440 --> 00:01:58,020 Remember that the order cannot be arbitrary 47 00:01:58,021 --> 00:02:01,800 and will be strictly first in first out. Once 48 00:02:01,801 --> 00:02:04,620 we learn the concept of channels, then we can 49 00:02:04,650 --> 00:02:06,990 implement complicated stuff such as chat 50 00:02:06,991 --> 00:02:09,240 system or program in which many threads 51 00:02:09,241 --> 00:02:12,030 perform part of a calculation, and one thread 52 00:02:12,031 --> 00:02:14,550 combines or aggregates the final result. 53 00:02:15,510 --> 00:02:17,550 Let's see how channels are created in code. 54 00:02:18,000 --> 00:02:20,370 First, we will bring the thread module and 55 00:02:20,371 --> 00:02:22,410 the message passing module into scope. 56 00:02:22,411 --> 00:02:29,370 [No Audio] 57 00:02:29,371 --> 00:02:32,100 The mpsc stands for Multiple producer 58 00:02:32,130 --> 00:02:34,800 single consumer. This means that the Rusts 59 00:02:34,801 --> 00:02:37,020 implementation of channels allows to have 60 00:02:37,021 --> 00:02:39,120 multiple sending ads for the data that 61 00:02:39,121 --> 00:02:42,150 produces values, but only one receiving and 62 00:02:42,180 --> 00:02:44,760 that consumes those values. The details of 63 00:02:44,761 --> 00:02:48,060 this will become obvious during the video. In 64 00:02:48,061 --> 00:02:50,670 this very basic example we will consider a 65 00:02:50,671 --> 00:02:53,310 single producer, but we will aid multiple 66 00:02:53,311 --> 00:02:56,220 producers later on. Moreover, we will create 67 00:02:56,221 --> 00:02:58,470 a thread which will be communicated with a 68 00:02:58,471 --> 00:03:00,960 main thread. In fact that thread will create 69 00:03:00,961 --> 00:03:03,330 some data which will be passed to the main 70 00:03:03,331 --> 00:03:06,330 thread. The channel function is used to 71 00:03:06,331 --> 00:03:08,966 create a channel which returns a tuple. 72 00:03:08,967 --> 00:03:10,400 Let us use this function. 73 00:03:10,401 --> 00:03:17,039 [No Audio] 74 00:03:17,040 --> 00:03:19,259 The function returns a tuple containing two 75 00:03:19,260 --> 00:03:21,839 elements. The first returning element is the 76 00:03:21,840 --> 00:03:24,509 sending end or the transmitting and the 77 00:03:24,510 --> 00:03:27,809 second returning element is the receiver and 78 00:03:27,839 --> 00:03:29,300 or the receiver. 79 00:03:30,271 --> 00:03:32,489 The abbreviations tx and rx 80 00:03:32,490 --> 00:03:34,229 are traditionally used for referring to the 81 00:03:34,230 --> 00:03:37,079 transmitter and receiver respectively. The 82 00:03:37,080 --> 00:03:39,119 variables are therefore named accordingly. 83 00:03:39,239 --> 00:03:41,639 The last statement destructures the 84 00:03:41,640 --> 00:03:45,233 tuple into the two variables, let us create a new thread. 85 00:03:45,234 --> 00:03:50,669 [No Audio] 86 00:03:50,670 --> 00:03:53,009 This thread will be acting as a producer so 87 00:03:53,010 --> 00:03:55,649 therefore it will need to use the sender tx 88 00:03:55,650 --> 00:03:58,769 variable the move ensures that it takes the 89 00:03:58,770 --> 00:04:01,000 ownership of the variable tx for this purpose. 90 00:04:01,533 --> 00:04:03,209 Please note that the spawn thread 91 00:04:03,210 --> 00:04:05,549 needs to own the transmitter to be able to 92 00:04:05,550 --> 00:04:08,879 send out messages through the channel. I will 93 00:04:08,880 --> 00:04:11,733 next create a string variable containing some values. 94 00:04:11,734 --> 00:04:17,970 [No Audio] 95 00:04:17,971 --> 00:04:19,920 I will add a print statement also. 96 00:04:19,921 --> 00:04:25,890 [No Audio] 97 00:04:25,891 --> 00:04:28,260 Finally I will use the send method on the tx 98 00:04:28,261 --> 00:04:30,780 variable and we'll pass to it the variable to 99 00:04:30,781 --> 00:04:32,070 send to the main function. 100 00:04:32,071 --> 00:04:37,110 [No Audio] 101 00:04:37,111 --> 00:04:40,080 The Send method returns a result type. If the 102 00:04:40,081 --> 00:04:42,330 receiver has already been dropped and there 103 00:04:42,331 --> 00:04:44,730 is no where to send a value, the send 104 00:04:44,731 --> 00:04:46,800 operation will return an error. In this 105 00:04:46,801 --> 00:04:49,260 example we are calling the unwrap to panic in 106 00:04:49,261 --> 00:04:51,660 case of an error. Please note that calling 107 00:04:51,661 --> 00:04:54,570 the unwrap or an error generates a 108 00:04:54,571 --> 00:04:57,210 panic in a real application we would handle 109 00:04:57,211 --> 00:04:59,400 it properly and will not cause the program to 110 00:04:59,401 --> 00:05:03,300 panic on errors. Let us now add some code 111 00:05:03,301 --> 00:05:05,250 for receiving the value that has been sent 112 00:05:05,251 --> 00:05:07,410 out by the thread. The receiver is a function 113 00:05:07,411 --> 00:05:09,810 called receive, which is used to receive 114 00:05:09,811 --> 00:05:12,266 values from the sender, let us use this function. 115 00:05:12,267 --> 00:05:17,520 [No Audio] 116 00:05:17,521 --> 00:05:19,470 This function blocks the thread which calls 117 00:05:19,471 --> 00:05:22,230 it, and wait until the value is sent down the 118 00:05:22,231 --> 00:05:24,570 channel. In this case it is erased since it 119 00:05:24,571 --> 00:05:26,430 is being invoked by the main thread. So, 120 00:05:26,431 --> 00:05:28,110 therefore, it will block the main thread 121 00:05:28,140 --> 00:05:31,770 execution and will wait until a value 122 00:05:31,771 --> 00:05:34,590 is sent down the channel. Once a value is 123 00:05:34,591 --> 00:05:36,930 sent, the receive function will return it 124 00:05:36,931 --> 00:05:39,766 inside an ok variant of the result enum. 125 00:05:40,266 --> 00:05:43,080 This means that this function will also return a 126 00:05:43,081 --> 00:05:45,720 result which either contains a value which is 127 00:05:45,721 --> 00:05:47,940 being sent out or an error, in case 128 00:05:48,150 --> 00:05:51,300 transmitter closes before even sending out a 129 00:05:51,301 --> 00:05:54,510 useful value. The error is used to signal date 130 00:05:54,511 --> 00:05:57,300 no more values will be coming. Finally, I 131 00:05:57,301 --> 00:05:58,920 will print out the value that has been 132 00:05:58,921 --> 00:06:01,233 received from the thread inside a print statement. 133 00:06:01,234 --> 00:06:06,720 [No Audio] 134 00:06:06,721 --> 00:06:09,100 Let us execute now to see the program in action. 135 00:06:09,101 --> 00:06:13,600 [No Audio] 136 00:06:13,601 --> 00:06:15,660 The program will always produce this 137 00:06:15,661 --> 00:06:17,760 output this is because the main is being 138 00:06:17,761 --> 00:06:19,620 blocked until the message from the thread has 139 00:06:19,621 --> 00:06:22,320 been received. If I add another statement 140 00:06:22,321 --> 00:06:24,120 after passing the message, then the program 141 00:06:24,121 --> 00:06:25,710 output may be changed during different 142 00:06:25,711 --> 00:06:29,310 executions. Let me add another print 143 00:06:29,311 --> 00:06:30,240 statement to the thread. 144 00:06:30,241 --> 00:06:35,490 [No Audio] 145 00:06:35,513 --> 00:06:37,200 I will now execute a few times. 146 00:06:37,201 --> 00:06:42,266 [No Audio] 147 00:06:42,267 --> 00:06:44,910 You may note that the last print statement is executed 148 00:06:44,911 --> 00:06:47,220 sometime before the main end sometime after. 149 00:06:48,780 --> 00:06:50,790 Now, let us explain a few points with regards 150 00:06:50,791 --> 00:06:53,533 to the ownership of the variables of rx and tx. 151 00:06:54,533 --> 00:06:56,520 From the type of the rx and tx. We may 152 00:06:56,521 --> 00:06:58,560 note that they are owned values and not 153 00:06:58,561 --> 00:07:01,980 references. This means that they are 154 00:07:02,010 --> 00:07:04,200 assuming the ownership of the respective 155 00:07:04,201 --> 00:07:07,800 values of type sender and receiver. Now if I 156 00:07:07,801 --> 00:07:09,930 add a line before creating the thread where I 157 00:07:09,931 --> 00:07:13,100 moved the variable rx to another variable rx1. 158 00:07:14,000 --> 00:07:15,930 You may note that the ownership has been 159 00:07:15,931 --> 00:07:18,390 transferred and now rx is no more in scope. 160 00:07:18,630 --> 00:07:21,120 In this case, we are unable to use the rx as 161 00:07:21,121 --> 00:07:23,670 the value has been moved. Let me change back. 162 00:07:25,033 --> 00:07:26,430 The next point with regards to the 163 00:07:26,431 --> 00:07:28,440 ownership is that once a value is being sent 164 00:07:28,441 --> 00:07:31,260 out, it is no more with a thread and 165 00:07:31,261 --> 00:07:33,210 therefore its ownership will be transferred 166 00:07:33,211 --> 00:07:36,630 to the thread where it has been received. To 167 00:07:36,631 --> 00:07:38,430 see this I will add a print statement at the 168 00:07:38,431 --> 00:07:40,380 end of the thread where I will try to access 169 00:07:40,381 --> 00:07:41,560 the variable which has been 170 00:07:41,561 --> 00:07:42,933 sent out to the main thread. 171 00:07:42,934 --> 00:07:48,030 [No Audio] 172 00:07:48,031 --> 00:07:50,070 You may note that the compiler is not happy 173 00:07:50,100 --> 00:07:52,860 telling us that borrow of a moved value. 174 00:07:54,480 --> 00:07:56,730 This is however, not the case with the 175 00:07:56,731 --> 00:07:59,130 primitives as they are not moved but are 176 00:07:59,131 --> 00:08:01,530 rather being copied. If I change the type of 177 00:08:01,531 --> 00:08:03,166 the variable to date of an integer. 178 00:08:03,167 --> 00:08:06,233 [No Audio] 179 00:08:06,234 --> 00:08:09,090 You may note that, the compiler has no issues with this. 180 00:08:09,840 --> 00:08:12,270 Let me comment out the last two print lines 181 00:08:12,271 --> 00:08:14,266 in the thread for now and move to the next topic. 182 00:08:14,267 --> 00:08:18,333 [No Audio] 183 00:08:18,334 --> 00:08:20,100 Similar to the receive function, we 184 00:08:20,101 --> 00:08:22,890 have a try receive function, this function is 185 00:08:22,891 --> 00:08:25,950 however non blocking in nature when called it 186 00:08:25,951 --> 00:08:28,200 will immediately return a result if the 187 00:08:28,201 --> 00:08:30,090 message is currently not available then it 188 00:08:30,091 --> 00:08:32,520 will return an error and if the message is 189 00:08:32,549 --> 00:08:36,000 available then it will return an ok. This 190 00:08:36,001 --> 00:08:38,370 method is very useful if the thread has other 191 00:08:38,371 --> 00:08:40,366 work to do while waiting for the messages. 192 00:08:41,265 --> 00:08:44,600 We could write a loop that calls a try_receive 193 00:08:44,601 --> 00:08:46,950 every so often handles a 194 00:08:46,951 --> 00:08:50,130 message if one is available and otherwise a 195 00:08:50,131 --> 00:08:52,560 does some other work for a little while 196 00:08:52,650 --> 00:08:55,890 until checking again. Let us see the use of 197 00:08:55,891 --> 00:08:57,690 this function but first I will comment out 198 00:08:57,691 --> 00:08:58,920 the lines in the main thread. 199 00:08:58,921 --> 00:09:04,260 [No Audio] 200 00:09:04,261 --> 00:09:06,210 First I will initialize a variable called 201 00:09:06,211 --> 00:09:08,580 received_status from false. 202 00:09:08,581 --> 00:09:13,980 [No Audio] 203 00:09:13,981 --> 00:09:16,560 This variable will be set to true once the 204 00:09:16,561 --> 00:09:18,660 try_receive function returns some 205 00:09:18,661 --> 00:09:21,840 useful value. Next I will create a while loop 206 00:09:21,900 --> 00:09:24,330 which will iterate as long as the variable 207 00:09:24,331 --> 00:09:26,430 received_status is not true. 208 00:09:26,431 --> 00:09:30,540 [No Audio] 209 00:09:30,541 --> 00:09:33,633 Inside the loop I will match on try_receive function. 210 00:09:33,634 --> 00:09:39,840 [No Audio] 211 00:09:39,841 --> 00:09:41,820 If it returns an ok variant then I will 212 00:09:41,821 --> 00:09:44,190 display the value which has been received and 213 00:09:44,191 --> 00:09:46,410 is being wrapped inside the ok variant. 214 00:09:46,411 --> 00:09:51,570 [No Audio] 215 00:09:51,571 --> 00:09:54,766 I will also set the value of received_status to true. 216 00:09:54,767 --> 00:09:59,600 [No Audio] 217 00:09:59,601 --> 00:10:01,100 In case of error, I will print out 218 00:10:01,101 --> 00:10:03,466 that I am doing some other useful stuff. 219 00:10:03,467 --> 00:10:11,370 [No Audio] 220 00:10:11,371 --> 00:10:13,666 This code will now and don't block the main thread. 221 00:10:13,933 --> 00:10:15,810 If there are multiple threads, they 222 00:10:15,811 --> 00:10:17,550 will get a chance as determined by the 223 00:10:17,551 --> 00:10:19,710 scheduling algorithm of the operating system. 224 00:10:19,770 --> 00:10:21,200 Let us cargo run this now. 225 00:10:21,201 --> 00:10:25,800 [No Audio] 226 00:10:25,801 --> 00:10:27,192 You may note that the man 227 00:10:27,193 --> 00:10:29,160 did not blocked and keep on doing 228 00:10:29,161 --> 00:10:32,670 some other stuff. Let us cover one more final 229 00:10:32,671 --> 00:10:36,233 point before we end. What will happen if I 230 00:10:36,234 --> 00:10:39,566 call are join before the code of try_receive 231 00:10:39,567 --> 00:10:40,766 in the main thread. 232 00:10:42,366 --> 00:10:45,690 Now, let's see this, I will assign the 233 00:10:45,691 --> 00:10:48,090 thread to variable t and then I will call the 234 00:10:48,091 --> 00:10:49,890 join on the variable t. 235 00:10:49,891 --> 00:10:55,620 [No Audio] 236 00:10:55,621 --> 00:10:57,510 In this case the main thread will be blocked 237 00:10:57,600 --> 00:11:00,433 until and unless the thread t is being complete. 238 00:11:00,633 --> 00:11:02,340 Afterwards the remaining of the 239 00:11:02,341 --> 00:11:04,470 code in the main will get a chance to execute 240 00:11:04,590 --> 00:11:06,100 let us cargo run this to see the output. 241 00:11:06,101 --> 00:11:08,700 [No Audio] 242 00:11:08,701 --> 00:11:11,430 This program will always produce this output, you 243 00:11:11,431 --> 00:11:13,440 may note that the main thread is never given 244 00:11:13,441 --> 00:11:15,540 a chance of doing something else. This is 245 00:11:15,541 --> 00:11:17,400 because the man is blocked until the thread 246 00:11:17,401 --> 00:11:19,710 goes to completion which ensures that we 247 00:11:19,740 --> 00:11:22,020 always have a valid message to receive once 248 00:11:22,021 --> 00:11:24,150 the thread is complete. Therefore we are 249 00:11:24,151 --> 00:11:27,150 unable to do any other stuff. Since the 250 00:11:27,151 --> 00:11:29,910 message is already available. This however 251 00:11:29,911 --> 00:11:32,130 has a disadvantage of blocking the main 252 00:11:32,131 --> 00:11:35,610 thread. With this we end this tutorial here 253 00:11:35,640 --> 00:11:37,890 there are many details about message passing, 254 00:11:37,891 --> 00:11:39,300 which we will be covering in the next 255 00:11:39,330 --> 00:11:41,143 tutorial. See you again and until then 256 00:11:41,144 --> 00:11:42,766 happy Rust programming 257 00:11:42,767 --> 00:11:48,066 [No Audio]