Rust Guide > Documentation > Concurrency > Sender

Introduction

In Rust, the Sender class is part of the standard library's std::sync::mpsc module, which stands for "multiple producer, single consumer." The Sender is used to send messages through a channel, which can then be received by a Receiver. Channels provide a way for different parts of your code to communicate with each other, especially in concurrent programming.

Using Sender

To use Sender, you need to create a channel using the std::sync::mpsc::channel function, which returns a (Sender, Receiver) pair. You can then use the Sender to send messages through the channel.

use std::sync::mpsc;
use std::thread;

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

    thread::spawn(move || {
        tx.send("Hello from the spawned thread!").unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Received: {}", received);
}
// Output:
// Received: Hello from the spawned thread!

Key Methods

Below are some of the key methods exposed by the Sender class:

send

Sends a value through the channel. This method will block if the channel's buffer is full. If the receiving end has been dropped, this method will return an Err.

use std::sync::mpsc;
use std::thread;

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

    thread::spawn(move || {
        tx.send(42).unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Received: {}", received);
}
// Output:
// Received: 42

clone

Creates a clone of the Sender. This is useful when you want multiple producers to send messages to the same receiver.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let tx1 = tx.clone();

    thread::spawn(move || {
        tx.send(1).unwrap();
    });

    thread::spawn(move || {
        tx1.send(2).unwrap();
    });

    for _ in 0..2 {
        let received = rx.recv().unwrap();
        println!("Received: {}", received);
    }
}
// Output (order may vary):
// Received: 1
// Received: 2

Example Usage

Example 1: Basic Usage

use std::sync::mpsc;
use std::thread;

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

    thread::spawn(move || {
        tx.send("Hello from the spawned thread!").unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Received: {}", received);
}
// Output:
// Received: Hello from the spawned thread!

Example 2: Sending Multiple Messages

use std::sync::mpsc;
use std::thread;

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

    thread::spawn(move || {
        tx.send(1).unwrap();
        tx.send(2).unwrap();
        tx.send(3).unwrap();
    });

    for _ in 0..3 {
        let received = rx.recv().unwrap();
        println!("Received: {}", received);
    }
}
// Output:
// Received: 1
// Received: 2
// Received: 3

Example 3: Using Clone for Multiple Senders

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let tx1 = tx.clone();

    thread::spawn(move || {
        tx.send(1).unwrap();
    });

    thread::spawn(move || {
        tx1.send(2).unwrap();
    });

    for _ in 0..2 {
        let received = rx.recv().unwrap();
        println!("Received: {}", received);
    }
}
// Output (order may vary):
// Received: 1
// Received: 2

Example 4: Handling Errors When the Receiver is Dropped

use std::sync::mpsc;
use std::thread;

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

    drop(rx); // Drop the receiver

    match tx.send(42) {
        Ok(_) => println!("Message sent successfully"),
        Err(e) => println!("Failed to send message: {}", e),
    }
}
// Output:
// Failed to send message: sending on a closed channel

Example 5: Using with Multiple Threads

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let tx1 = tx.clone();

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

    let handle2 = thread::spawn(move || {
        for i in 5..10 {
            tx1.send(i).unwrap();
        }
    });

    handle1.join().unwrap();
    handle2.join().unwrap();

    for received in rx {
        println!("Received: {}", received);
    }
}
// Output:
// Received: 0
// Received: 1
// Received: 2
// Received: 3
// Received: 4
// Received: 5
// Received: 6
// Received: 7
// Received: 8
// Received: 9

Considerations

  • Using Sender::clone, you can create multiple producers for a single receiver. Each clone can send messages independently.
  • Always handle the Result returned by send to manage possible errors when the receiver is dropped.
  • Dropping the Sender will close the sending side of the channel, causing the receiver to return an error once all messages have been received.

See Also

  • Receiver - The receiving half of a channel used to receive messages.
  • JoinHandle - A handle for managing the lifecycle of a thread.
  • Mutex - A mutual exclusion primitive for protecting shared data.