Day19:Communicating via MPSC channel - 100DayOfRust
Tags: rust
Published: 2019-12-05 04:08:01

### Example 1

```rust
use std::thread;
use std::sync::mpsc;

fn main() {
    let (sender, recver) = mpsc::channel();
    thread::spawn(move || {
        sender.send("hello world").unwrap();
    });
    let s = recver.recv().unwrap();
    println!("Received: {}", s); 
}
```

Result:
```
Received: hello world
```

### Example 2

```rust
use std::thread;
use std::time;
use std::sync::mpsc;

fn main() {
    let (sender, recver) = mpsc::channel();

    thread::spawn(move || {
        let list = vec![
            "hello".to_owned(),
            "world".to_owned(),
            "and".to_owned(),
            "rust".to_owned(),
        ];
        for s in list {
            sender.send(s).unwrap();
            thread::sleep(time::Duration::from_secs(1));
        }
    }); 
    for s in recver {
        println!("Received: {}", s); 
    }   
}
```

Result:
```
Received: hello
Received: world
Received: and
Received: rust
```

### Example 3

```rust
use std::thread;
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();
    let job_count = 10; 

    for i in 0..job_count {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(i).unwrap();
        });
    }   

    for _i in 0..job_count {
        println!("Recv: {}", rx.recv().unwrap());
    }
}
```

Result: (b/c the result returned in thread, your print might be different)
```
Recv: 0
Recv: 1
Recv: 3
Recv: 2
Recv: 5
Recv: 4
Recv: 6
Recv: 7
Recv: 8
Recv: 9
```

In this example, we have 11 sender side (`tx` in the code) open, the original tx and cloned 10 tx. The opened tx in thread will be closed once the thread finished running. This means after running 10 threads, we still have 1 `tx` open. For `rx` we call `recv` 10 times then close.

We could also treat `rx` as iterator, use `for .. in` to receive the passed number:

```rust
use std::thread;
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();
    let job_count = 10; 

    for i in 0..job_count {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(i).unwrap();
        });
    }   

    for num in rx {
        println!("Recv: {}", num);
    }   
}
```

If we run this, we will get something like:
```
Recv: 1
Recv: 2
Recv: 3
Recv: 4
Recv: 0
Recv: 6
Recv: 5
Recv: 7
Recv: 8
Recv: 9

```

But then our program is blocked, it keeps waiting for message in `rx`, the program won't quit. The problem is, when we use `for .. in`, system will keep trying to get message from channel until all sender ends close. Like we mentioned above, we have opened 11 sender ends, and thread closed 10, there is still one left open - the original one. So we need to close the original one:

```rust
use std::thread;
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();
    let job_count = 10; 

    for i in 0..job_count {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(i).unwrap();
        });
    }
    // we close the original sender end   
    drop(tx);

    for num in rx {
        println!("Recv: {}", num);
    }   
}
```

Now our program can run and exit successfully after receiving all message from the channel.
```
Recv: 0
Recv: 1
Recv: 2
Recv: 4
Recv: 5
Recv: 3
Recv: 7
Recv: 6
Recv: 9
Recv: 8
```