Blog Archives
migration C#, Java, C++ (day 11), future and promise
There is hardly anything directly to compare with in C#. Future and promise are C++ concepts, which are probably best compared to C# task concepts. The comparison was not easy today. Have a look at the outcome.
future and promise
using System; using System.Threading; using System.Threading.Tasks; namespace Program { public class Day11 { private class Params { public int Input; public int Result; } private void DoSomething() { Console.WriteLine("DoSomething()"); Thread.Sleep(4000); } // private void Method1(object xObject) { Params lParams = xObject as Params; Console.WriteLine("Method1"); Thread.Sleep(2000); lParams.Result = 2 * lParams.Input; } // private int Method2(int xInt1) { Console.WriteLine("Method2"); Thread.Sleep(2000); return 2 * xInt1; } // private async Task<int> Method3(int xInt1) { await Task.Delay(0); Console.WriteLine("Method3"); return 2 * xInt1; } // private void Method4(Params xParams, AutoResetEvent xEvent) { Console.WriteLine("Method4"); Thread.Sleep(2000); xEvent.WaitOne(); xParams.Result = 2 * xParams.Input; } // static void Main(string[] args) { Day11 lDay10 = new Day11(); lDay10.test(); } // public async void test() { int i; // use a thread to get an asynchronous result ParameterizedThreadStart lParams = new ParameterizedThreadStart(Method1); Thread thread1 = new Thread(lParams); Params p = new Params() { Input = 123 }; thread1.Start(p); Console.WriteLine("Method1.join()"); thread1.Join(); Console.WriteLine("Method1 result is: " + p.Result); Func<int, int> t1 = new Func<int, int>(x => { return Method2(x); }); i = t1(123); // synchronous IAsyncResult lResult = t1.BeginInvoke(123, null, null); // asynchronously lResult.AsyncWaitHandle.WaitOne(); i = await Method3(123); Console.WriteLine("Method3 result is: " + i); p.Input = 123; p.Result = 0; AutoResetEvent lEvent = new AutoResetEvent(false); Task t2 = new Task(() => Method4(p, lEvent)); t2.Start(); lEvent.Set(); t2.Wait(); Console.WriteLine("Method4 result is: " + p.Result); Console.ReadLine(); } // } // class } // namespace
example output:
Method1.join()
Method1
Method1 result is: 246
Method2
Method2
Method3
Method3 result is: 246
Method4
Method4 result is: 246
#include <future> #include <iostream> #include <thread> using namespace std; void DoSomething() { cout << "DoSomething()" << endl; this_thread::sleep_for(chrono::seconds(4)); } // void Thread1(int xInt1, int &xInt2) { cout << "Thread1" << endl; this_thread::sleep_for(chrono::seconds(2)); xInt2 = 2 * xInt1; } // int Thread2(int xInt1) { cout << "Thread2" << endl; this_thread::sleep_for(chrono::seconds(2)); return 2 * xInt1; } // int Thread3(future<int> &xInt1) { cout << "Thread3" << endl; this_thread::sleep_for(chrono::seconds(2)); return 2 * xInt1.get(); // .get() => waits until the promise is fullfilled } // int Thread4(shared_future<int> xInt1) { cout << "Thread4" << endl; this_thread::sleep_for(chrono::seconds(2)); return 2 * xInt1.get(); // returns the same value to all waiting futures } // void test(){ int i; // use a thread to get an asynchronous result thread t1(Thread1, 123, ref(i)); cout << "Thread1.join()" << endl; t1.join(); cout << "Thread1 result is: " << i << endl; // like a task, may be synchronous or asychronous future<int> f1 = async(Thread2, 123); cout << "Thread2, f1.get()" << endl; i = f1.get(); // waits // like a synchronous task, which is running on the same thread // will be called when you get the value future<int> f2 = async(launch::deferred, Thread2, 123); cout << "Thread2, f2.get()" << endl; i = f2.get(); // waits cout << "Thread2 deferred result is: " << i << endl; // like an asynchronous task, which is running on a new thread future<int> f3 = async(launch::async, Thread2, 123); cout << "Thread2, f3.get()" << endl; i = f3.get(); // waits cout << "Thread2 async result is: " << i << endl; // same as f1, because this is the default value; the system decides what to do future<int> f4 = async(launch::async | launch::deferred, Thread2, 123); i = f4.get(); // waits promise<int> lPromise5; // promise to provide a value at a later time future<int> f5 = lPromise5.get_future(); future<int> f5b = async(launch::async, Thread3, ref(f5)); DoSomething(); cout << "lPromise5.set_value()" << endl; lPromise5.set_value(123); // fulfill our promise now cout << "f5b async result is: " << f5b.get() << endl; promise<int> lPromise6; // promise to provide a value at a later time future<int> f6 = lPromise6.get_future(); DoSomething(); // tell the parallel thread to stop waiting for the promise fulfillment lPromise6.set_exception(make_exception_ptr(runtime_error("sorry, I cannot fulfill my promise"))); // // SOME PRACTICAL ISSUES // promise<int> lPromise7; // promise to provide a value at a later time future<int> f7 = lPromise7.get_future(); promise<int> lPromise8 = move(lPromise7); // you cannot assign a promise, you have to move it future<int> f8 = move(f7); // same with the future // you cannot call future.get() more than once // to allow multiple consumers use: shared_future<int> f9 = f8.share(); future<int> f10 = async(launch::async, Thread4, f9); future<int> f11 = async(launch::async, Thread4, f9); future<int> f12 = async(launch::async, Thread4, f9); future<int> f13 = async(launch::async, Thread4, f9); lPromise8.set_value(123); cout << "f10: " << f10.get() << ", f11:" << f11.get() << ", f12:" << f12.get() << ", f13:" << f13.get() << endl; // packaged_task auto t2 = bind(Thread2, 123); t2(); // synchronous packaged_task<int()> t3(bind(Thread2, 123)); // wrapper to make async calls t3(); // call the task in a different context future<int> f14 = t3.get_future(); // getting a future is not possible with t2 int x = f14.get(); cout << "f14: " << x << endl; cin.get(); } //
example output:
Thread1.join()
Thread1Thread1 result is: 246
Thread2, f1.get()
Thread2Thread2, f2.get()
Thread2
Thread2 deferred result is: 246
Thread2, f3.get()
Thread2Thread2 async result is: 246
Thread2
DoSomething()
Thread3lPromise5.set_value()
f5b async result is: 246
DoSomething()
Thread4
Thread4Thread4
Thread4
f10: 246, f11:246, f12:246, f13:246
Thread2
Thread2
f14: 246
package Program; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Day11 { private static void Sleep(int xMilliseconds) { try { Thread.sleep(xMilliseconds); } catch (InterruptedException ex) { System.err.println(ex.getMessage()); } } // private class Thread1 extends Thread { public int Input; public int Result; @Override public void run() { System.out.println("Thread1"); Sleep(2000); Result = 2 * Input; } // } // class private class Thread2 { private final ExecutorService pool = Executors.newFixedThreadPool(5); public Future<Integer> getPromise(final int xInt1) { return pool.submit(() -> { System.out.println("Thread2"); Sleep(2000); return 2 * xInt1; }); } // } // class private class Thread3 implements Callable<Integer> { private final ExecutorService _Pool = Executors.newFixedThreadPool(5); private int _Int1; public Future<Integer> getPromise(final int xInt1) { _Int1 = xInt1; return _Pool.submit(this); } // @Override public Integer call() throws Exception { synchronized (this) { this.wait(); } System.out.println("Thread3"); Sleep(2000); return 2 * _Int1; } // } // class public final void test() throws InterruptedException, ExecutionException { // use a thread to get an asynchronous result Thread1 t1 = new Thread1(); t1.Input = 123; t1.start(); System.out.println("Thread1.join()"); t1.join(); System.out.println("Thread1 result is: " + t1.Result); // like a task, may be synchronous or asychronous Thread2 t2 = new Thread2(); Future<Integer> f1 = t2.getPromise(123); System.out.println("Thread2, f1.getPromise(123)"); int i = f1.get(); // waits System.out.println("f1 result is: " + i); // deferred Thread3 t3 = new Thread3(); Future<Integer> f2 = t3.getPromise(123); synchronized (t3) { t3.notify(); // start calculation manually } System.out.println("Thread3 result is: " + f2.get()); // wait new Scanner(System.in).nextLine(); } // public static void main(String[] args) throws InterruptedException, ExecutionException { Day11 lDay11 = new Day11(); lDay11.test(); } // } // class
example output:
Thread1
Thread1.join()
Thread1 result is: 246
Thread2
Thread2, f1.getPromise(123)
f1 result is: 246
Thread3
Thread3 result is: 246