Non Blocking Channel Operations in C++

#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <chrono>
#include <atomic>

int main() {
    std::vector<std::string> messages;
    std::vector<bool> signals;
    std::atomic<bool> messageReady(false);
    std::atomic<bool> signalReady(false);

    // Here's a non-blocking receive. If a value is
    // available in `messages` then the if condition will be true
    // and we'll process the message. If not, it will immediately
    // take the else branch.
    if (messageReady.load()) {
        std::string msg = messages.back();
        messages.pop_back();
        std::cout << "received message " << msg << std::endl;
    } else {
        std::cout << "no message received" << std::endl;
    }

    // A non-blocking send works similarly. Here `msg`
    // is added to the `messages` vector only if `messageReady`
    // is false, simulating a non-blocking send.
    std::string msg = "hi";
    if (!messageReady.load()) {
        messages.push_back(msg);
        messageReady.store(true);
        std::cout << "sent message " << msg << std::endl;
    } else {
        std::cout << "no message sent" << std::endl;
    }

    // We can use multiple conditions to implement a multi-way
    // non-blocking select. Here we attempt non-blocking receives
    // on both `messages` and `signals`.
    if (messageReady.load()) {
        std::string msg = messages.back();
        messages.pop_back();
        std::cout << "received message " << msg << std::endl;
    } else if (signalReady.load()) {
        bool sig = signals.back();
        signals.pop_back();
        std::cout << "received signal " << std::boolalpha << sig << std::endl;
    } else {
        std::cout << "no activity" << std::endl;
    }

    return 0;
}

This C++ code demonstrates non-blocking operations similar to the original example. However, C++ doesn’t have built-in channels or a select statement like some other languages. Instead, we use std::vector to simulate channels and std::atomic variables to control access to these vectors in a thread-safe manner.

Here’s how the concepts are translated:

  1. Channels are simulated using std::vector<std::string> for messages and std::vector<bool> for signals.
  2. Non-blocking operations are implemented using std::atomic<bool> flags (messageReady and signalReady) to indicate whether a message or signal is available.
  3. The select statement is replaced with a series of if-else conditions checking these atomic flags.
  4. Sending a message is simulated by pushing to the vector and setting the corresponding atomic flag.
  5. Receiving a message is simulated by checking the atomic flag, and if true, popping from the vector.

This code provides a similar functionality to the original, demonstrating non-blocking operations in C++. However, it’s important to note that this is a simplified simulation and doesn’t provide all the guarantees and features of actual channel-based concurrency primitives.

To compile and run this program:

$ g++ -std=c++11 -pthread non_blocking_operations.cpp -o non_blocking_operations
$ ./non_blocking_operations
no message received
sent message hi
no activity

The output may vary depending on the timing of operations, which is expected in concurrent scenarios.