Task: Active object


C++: #include <atomic>
#include <chrono>
#include <cmath>
#include <iostream>
#include <mutex>
#include <thread>

using namespace std::chrono_literals;

class Integrator
{
  public:
    using clock_type = std::chrono::high_resolution_clock;
    using dur_t      = std::chrono::duration<double>;
    using func_t     = double(*)(double);

    explicit Integrator(func_t f = nullptr);
    ~Integrator();
    void input(func_t new_input);
    double output() { return integrate(); }

  private:
    std::atomic_flag continue_;
    std::mutex       mutex;
    std::thread      worker;

    func_t                       func;
    double                       state = 0;
    
    clock_type::time_point const beginning = clock_type::now();
    clock_type::time_point       t_prev = beginning;

    void do_work();
    double integrate();
};

Integrator::Integrator(func_t f) : func(f)
{
    continue_.test_and_set();
    worker = std::thread(&Integrator::do_work, this);
}

Integrator::~Integrator()
{
    continue_.clear();
    worker.join();
}

void Integrator::input(func_t new_input)
{
    integrate();
    std::lock_guard<std::mutex> lock(mutex);
    func = new_input;
}

void Integrator::do_work()
{
    while (continue_.test_and_set()) {
        integrate();
        std::this_thread::sleep_for(1ms);
    }
}

double Integrator::integrate()
{
    std::lock_guard<std::mutex> lock(mutex);
    auto now = clock_type::now();
    dur_t start = t_prev - beginning;
    dur_t fin   =    now - beginning;
    if (func)
        state += (func(start.count()) + func(fin.count())) * (fin - start).count() / 2;
    t_prev = now;
    return state;
}

double sine(double time)
{
    constexpr double PI = 3.1415926535897932;
    return std::sin(2 * PI * 0.5 * time);
}

int main()
{
    Integrator foo(sine);
    std::this_thread::sleep_for(2s);
    foo.input(nullptr);
    std::this_thread::sleep_for(500ms);
    std::cout << foo.output();
}



Go: package main

import (
    "fmt"
    "math"
    "time"
)



type tFunc func(time.Duration) float64



type aio struct {
    iCh chan tFunc        
    oCh chan chan float64 
}


func newAio() *aio {
    var a aio
    a.iCh = make(chan tFunc)
    a.oCh = make(chan chan float64)
    go aif(&a)
    return &a
}




func (a aio) input(f tFunc) {
    a.iCh <- f
}




func (a aio) output() float64 {
    sCh := make(chan float64)
    a.oCh <- sCh
    return <-sCh
}


func zeroFunc(time.Duration) float64 { return 0 }


func aif(a *aio) {
    var k tFunc = zeroFunc 
    s := 0.                
    t0 := time.Now()       
    k0 := k(0)             
    t1 := t0               
    k1 := k0

    tk := time.Tick(10 * time.Millisecond) 
    for {
        select {
        case t2 := <-tk: 
            k2 := k(t2.Sub(t0))                        
            s += (k1 + k2) * .5 * t2.Sub(t1).Seconds() 
            t1, k1 = t2, k2                            
        case k = <-a.iCh: 
        case sCh := <-a.oCh: 
            sCh <- s
        }
    }
}

func main() {
    a := newAio()                           
    a.input(func(t time.Duration) float64 { 
        return math.Sin(t.Seconds() * math.Pi)
    })
    time.Sleep(2 * time.Second) 
    a.input(zeroFunc)           
    time.Sleep(time.Second / 2) 
    fmt.Println(a.output())     
}