Non Blocking Channel Operations in Cilk

Our example demonstrates non-blocking operations on channels using Cilk++. In Cilk++, we can use cilk::chan for channel-like communication between tasks, and cilk_spawn for creating concurrent tasks.

#include <cilk/cilk.h>
#include <cilk/cilk_api.h>
#include <cilk/reducer_opadd.h>
#include <cilk/cilk_io.h>
#include <iostream>
#include <string>

int main() {
    cilk::chan<std::string> messages;
    cilk::chan<bool> signals;

    // Here's a non-blocking receive. If a value is
    // available on `messages` then it will be received.
    // If not, it will immediately take the else branch.
    if (messages.try_recv()) {
        std::string msg;
        messages >> msg;
        std::cout << "received message " << msg << std::endl;
    } else {
        std::cout << "no message received" << std::endl;
    }

    // A non-blocking send works similarly. Here `msg`
    // cannot be sent to the `messages` channel if it's full,
    // so the else branch is taken.
    std::string msg = "hi";
    if (messages.try_send(msg)) {
        std::cout << "sent message " << msg << std::endl;
    } else {
        std::cout << "no message sent" << std::endl;
    }

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

    return 0;
}

This code demonstrates non-blocking operations using Cilk++. While Cilk++ doesn’t have a direct equivalent to Go’s select statement, we can achieve similar functionality using try_recv() and try_send() methods on cilk::chan objects.

The program creates two channels: messages for strings and signals for booleans. It then performs three non-blocking operations:

  1. A non-blocking receive on messages.
  2. A non-blocking send on messages.
  3. A multi-way non-blocking receive on both messages and signals.

In each case, if the operation can be performed immediately, it is executed. If not, the program continues without blocking.

To run this program, you would compile it with a Cilk++ compatible compiler and then execute the resulting binary:

$ g++ -fcilkplus non_blocking_operations.cpp -o non_blocking_operations
$ ./non_blocking_operations
no message received
no message sent
no activity

This example showcases how to implement non-blocking channel operations in Cilk++, providing a way to handle concurrent communication without blocking the main execution flow.