Task Parallel Library - How do you get a Continuation with TaskContinuationOptions.OnlyOnCanceled to Fire? - task-parallel-library

I'm experimenting with the Task support in .NET 4.0 - specifically with the continuation support. What I'm perplexed about is that I can't figure out how to get a continuation with the TaskContinuationOptions.OnlyOnCanceled flag set to execute. If I do a ThrowIfCancellationRequested in my worker routine, it only seems to propagate out of the continuation as a fault instead of a cancel operation. For instance, given this code:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskExp1
{
class Program
{
static void Main()
{
var n = 10000;
DumpThreadId("main method");
var cts = new CancellationTokenSource();
var task = Task.Factory.StartNew<int>(_ => Sum(cts.Token, n),
cts.Token);
task.ContinueWith(t =>
{
DumpThreadId("ContinueWith Completed, ", newline:false);
Console.WriteLine("The result is " + t.Result);
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(t =>
{
DumpThreadId("ContinueWith Faulted, ", newline: false);
Console.WriteLine(t.Exception.InnerExceptions[0].Message);
}, TaskContinuationOptions.OnlyOnFaulted);
task.ContinueWith(_ =>
{
DumpThreadId("ContinueWith Cancelled, ");
}, TaskContinuationOptions.OnlyOnCanceled);
Console.WriteLine("Computing sum of " + n + " ...");
Thread.SpinWait(100000);
cts.Cancel();
Console.WriteLine("Done.");
Console.ReadLine();
}
static int Sum(CancellationToken cancelToken, int n)
{
DumpThreadId("from Sum method");
int sum = 0;
for (; n > 0; n--)
{
Thread.SpinWait(500000);
if (n == 10000) cancelToken.ThrowIfCancellationRequested();
checked { sum += n; }
}
return sum;
}
static void DumpThreadId(string msg = "", bool newline = true)
{
var formattedMsg = String.Format("ThreadId: {0} {1}",
Thread.CurrentThread.ManagedThreadId, msg);
if (newline) formattedMsg += "\n";
Console.Write(formattedMsg);
}
}
}
This outputs:
ThreadId: 9 main method
Computing sum of 10000 ...
Done.
ThreadId: 10 from Sum method
ThreadId: 10 ContinueWith Faulted, The operation was canceled.
How do I exit my worker (Sum) method such that the OnlyOnCanceled continuation gets fired?

When you are using the _ => lambda expression you are using the
Func<Object, TResult> function, Object state
overload. If you change the Factory.StartNew to
Task.Factory.StartNew<int>(() => Sum(cts.Token, n), cts.Token);
it will call the "ContinueWith Cancelled".

Related

WebsocketConnection using libsoup-2.4 is sometimes blocking GTK ui thread and prevents opening the main window

I have a simple GTK app written in Vala with a websocket connection (using libsoup-2.4).
Problem: my app sometimes freezes at startup (each ~10th startups) and doesn't show the gui window at all because of blocking somewhere in libsoup on socket connection.
Vala 0.40.25 with
gtk+-3.0
glib-2.0
gobject-2.0
libsoup-2.4
Here the code:
using Gtk;
class WebsocketConnection {
private Soup.WebsocketConnection websocket_connection;
public signal void ws_message(int type, string message);
public signal void connection_succeeded();
public signal void connection_established();
public signal void connection_failed();
public signal void connection_disengaged();
private string host;
public WebsocketConnection(string host) {
this.host = host;
}
private static string decode_bytes(Bytes byt, int n) {
return (string)byt.get_data();
}
public void init_connection_for(string host) {
MainLoop loop = new MainLoop();
var socket_client = new Soup.Session();
string url = "ws://%s:8080/".printf(host);
message(#"connect to $url");
var websocket_message = new Soup.Message("GET", url);
socket_client.websocket_connect_async.begin(websocket_message, null, null, null, (obj, res) => {
try {
websocket_connection = socket_client.websocket_connect_async.end(res);
message("Connected!");
connection_succeeded();
if (websocket_connection != null) {
websocket_connection.message.connect((type, m_message) => {
ws_message(type, decode_bytes(m_message, m_message.length));
});
websocket_connection.closed.connect(() => {
message("Connection closed");
connection_disengaged();
});
}
} catch (Error e) {
message("Remote error: " + e.message + " " + e.code.to_string());
connection_failed();
loop.quit();
}
loop.quit();
});
loop.run();
}
}
class Main : Gtk.Application {
public Main() {
Object(
application_id: "com.github.syfds.websocket-libsoup-vala-example",
flags : ApplicationFlags.FLAGS_NONE
);
}
protected override void activate() {
var window = new ApplicationWindow(this);
window.title = "Hello, World!";
window.border_width = 10;
window.window_position = WindowPosition.CENTER;
window.set_default_size(350, 70);
window.destroy.connect(Gtk.main_quit);
var grid = new Grid();
grid.orientation = Orientation.VERTICAL;
grid.column_spacing = 5;
grid.row_spacing = 5;
var main_label = new Label("...");
var websocket_host_input = new Entry();
var send_message_btn = new Button.with_label("Connect");
var websocket_host = "192.168.1.252";
var connection = new WebsocketConnection(websocket_host);
connection.connection_succeeded.connect(() => {
message("Connection succeeded");
main_label.set_text("Connection succeeded");
});
connection.connection_failed.connect(() => {
message("Connection failed");
});
connection.ws_message.connect((type, msg) => {
message("message received " + msg);
});
connection.init_connection_for(websocket_host);
grid.add(main_label);
window.add(grid);
window.show_all();
}
public static int main(string[] args) {
var app = new Main();
return app.run(args);
}
}
if I connect to the process over gdb I see following picture:
(gdb) info thr
Id Target Id Frame
* 1 Thread 0x7f38e6cbbac0 (LWP 29885) "com.github.syfd" 0x00007f38e53098f6 in __libc_recv (
fd=14, buf=0x55890440bc00, len=1024, flags=0) at ../sysdeps/unix/sysv/linux/recv.c:28
2 Thread 0x7f38d5d1c700 (LWP 29886) "gmain" 0x00007f38e52fbcb9 in __GI___poll (
fds=0x558903d13b40, nfds=2, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
3 Thread 0x7f38d551b700 (LWP 29887) "gdbus" 0x00007f38e52fbcb9 in __GI___poll (
fds=0x558903d30760, nfds=2, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
4 Thread 0x7f38cffff700 (LWP 29888) "dconf worker" 0x00007f38e52fbcb9 in __GI___poll (
fds=0x558903f6ccb0, nfds=1, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
(gdb) bt
#0 0x00007f38e53098f6 in __libc_recv (fd=14, buf=0x55890440bc00, len=1024, flags=0)
at ../sysdeps/unix/sysv/linux/recv.c:28
#1 0x00007f38e5eb54f4 in () at /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#2 0x00007f38e5667558 in () at /usr/lib/x86_64-linux-gnu/libsoup-2.4.so.1
#3 0x00007f38e59173a5 in g_main_context_dispatch () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#4 0x00007f38e5917770 in () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#5 0x00007f38e59177fc in g_main_context_iteration () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#6 0x00007f38e5ed8f3d in g_application_run () at /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#7 0x0000558902d69e8f in main_main (args=0x7ffeb2b775f8, args_length1=1)
at /home/sergej/workspace/websocket-libsoup-vala-example-v2/src/Main.vala:121
#8 0x0000558902d69ed2 in main (argc=1, argv=0x7ffeb2b775f8)
at /home/sergej/workspace/websocket-libsoup-vala-example-v2/src/Main.vala:119
It looks like __libc_recv at ../sysdeps/unix/sysv/linux/recv.c:28 is blocking here but I can't understand why and how to do the connection on non-blocking way.
I appreciate any help/hints how to solve the issue with blocked UI or how to create non-blocking websocket connection with libsoup.
You're using async methods, but it needs a bit of work. Make your init_connection_for method async:
public async void init_connection_for(string host) { ... }
then yield to the call to make the websocket connection:
var websocket_connection = yield socket_client.websocket_connect_async(websocket_message, null, null, null);
Then you call your function to set things up at the beginning before it then yields and gets called back by the asynchronous connection:
connection.init_connection_for.begin(websocket_host);
You then also need to compile with GIO, --pkg gio-2.0, for the async methods.
This will get you moving forwards, but there is a lot more that can be done to simplify and re-architect your code. You don't need the extra MainLoop for example.
This is a diff of the changes to help you progress:
--- original.vala 2021-08-08 15:59:41.757378207 +0100
+++ modifed.vala 2021-08-08 17:18:58.680837130 +0100
## -18,35 +18,33 ##
return (string)byt.get_data();
}
- public void init_connection_for(string host) {
+ public async void init_connection_for(string host) {
MainLoop loop = new MainLoop();
var socket_client = new Soup.Session();
string url = "ws://%s:8080/".printf(host);
message(#"connect to $url");
var websocket_message = new Soup.Message("GET", url);
- socket_client.websocket_connect_async.begin(websocket_message, null, null, null, (obj, res) => {
- try {
- websocket_connection = socket_client.websocket_connect_async.end(res);
- message("Connected!");
-
- connection_succeeded();
- if (websocket_connection != null) {
- websocket_connection.message.connect((type, m_message) => {
- ws_message(type, decode_bytes(m_message, m_message.length));
- });
- websocket_connection.closed.connect(() => {
- message("Connection closed");
- connection_disengaged();
- });
- }
- } catch (Error e) {
- message("Remote error: " + e.message + " " + e.code.to_string());
- connection_failed();
- loop.quit();
+ var websocket_connection = yield socket_client.websocket_connect_async(websocket_message, null, null, null);
+ try {
+ message("Connected!");
+
+ connection_succeeded();
+ if (websocket_connection != null) {
+ websocket_connection.message.connect((type, m_message) => {
+ ws_message(type, decode_bytes(m_message, m_message.length));
+ });
+ websocket_connection.closed.connect(() => {
+ message("Connection closed");
+ connection_disengaged();
+ });
}
+ } catch (Error e) {
+ message("Remote error: " + e.message + " " + e.code.to_string());
+ connection_failed();
loop.quit();
- });
+ }
+ loop.quit();
loop.run();
}
## -94,7 +92,7 ##
message("message received " + msg);
});
- connection.init_connection_for(websocket_host);
+ connection.init_connection_for.begin(websocket_host);
grid.add(main_label);
window.add(grid);
window.show_all();

How to sort List in dart based on value returned by a function

I have to show a list of stores in a sorted order by nearest location
and I have a unsorted list of stores and a function to calculate
distance of each store from my current location but I don't know how
to sort List in dart based on value returned by a function.
I am getting the unsorted List of stores data from an api.
I need logic for this question for sorting the _kikkleStores List
class KikkleStoresBloc extends BlocBase {
List<KikkleStoreInfo> _kikkleStores = [];
//for distance sorting
List<KikkleStoreInfo> _kikkleStoresSorted = [];
List<double> distanceFromCurrentLocation;//already got
value in it
bool hasReachedEndOfList = false;
Coordinate _currentLocation;
KikkleStoresBloc();
final _kikkleStoreSubject =
BehaviorSubject<List<KikkleStoreInfo>>
();
// Getter Stream
Stream<List<KikkleStoreInfo>> get kikkleStores =>
_kikkleStoreSubject.stream;`enter code here`
// Getter Sink
Function(List<KikkleStoreInfo>) get _fetchedkikkleStores =>
_kikkleStoreSubject.sink.add;
getKikkleStores() async {
try {
if (_currentPage <= _totalPages) {
final response = await
ApiController.getKikkleStores(_currentPage);
_kikkleStores.addAll(response.item1);
//here how to sort _kikkleStores by using
getStoreDistance function
_totalPages = response.item3;
_fetchedkikkleStores(_kikkleStores);
if (_currentPage == _totalPages) {
hasReachedEndOfList = true;
} else if (_currentPage < _totalPages &&
_kikkleStores.length
< 10) {
}
}
}
}
// this function returns distance
getStoreDistance(Coordinate currentLocation, KikkleStoreInfo
store)
async {
if (currentLocation == null) return 0.0;
try {
double distanceInMeter = await
LocationUtils.getDistanceInMeters(
currentLocation, Coordinate(store.latitude,
store.longitude));
// final miles = (distanceInMeter / 1609.344).round();
return distanceInMeter;
} catch (e) {
return 0.0;
}
}
void getCurrentLocation() async {
try {
final isAllowed = await
PermissionsUtils.isLocationAccessAllowed();
if (isAllowed) {
final coordinates = await
LocationUtils.getCurrentLocation();
if (coordinates != null) {
_currentLocation = coordinates;
}
}
}
catch (e) {
print(e);
}
}
}
Take the reference of below code
void main(){
List<POJO> pojo = [POJO(5), POJO(3),POJO(7),POJO(1)];
// fill list
pojo..sort((a, b) => a.id.compareTo(b.id));
for(var i in pojo){
print(i.id); // prints list in sorted order i.e 1 3 5 7
}
}
class POJO {
int id;
POJO(this.id);
}
void sortfun() async {
for (int c = 0; c < (_kikkleStores.length - 1); c++) {
for (int d = 0; d < _kikkleStores.length - c - 1; d++) {
if (await getStoreDistance(_currentLocation, _kikkleStores[d]) >
await getStoreDistance(_currentLocation,
_kikkleStores[d + 1])) /* For descending order use < */
{
swap = _kikkleStores[d];
_kikkleStores[d] = _kikkleStores[d + 1];
_kikkleStores[d + 1] = swap;
}
}
}
}

How do you use linq to group records based on an accumulator?

Given an enumeration of records in the format:
Name (string)
Amount (number)
For example:
Laverne 4
Lenny 2
Shirley 3
Squiggy 5
I want to group the records, so that each group's total Amount does not exceed some limit-per-group. For example, 10.
Group 1 (Laverne,Lenny,Shirley) with Total Amount 9
Group 2 (Squiggy) with Total Amount 5
The Amount number is guaranteed to always be less than the grouping limit.
If you allow for captured variables to maintain state, then it becomes easier. If we have:
int limit = 10;
Then:
int groupTotal = 0;
int groupNum = 0;
var grouped = records.Select(r =>
{
int newCount = groupTotal + r.Amount;
if (newCount > limit)
{
groupNum++;
groupTotal = r.Amount;
}
else
groupTotal = newCount;
return new{Records = r, Group = groupNum};
}
).GroupBy(g => g.Group, g => g.Records);
It's O(n), and just a Select and a GroupBy, but the use of captured variables may not be as portable across providers as one may want though.
For linq-to-objects though, it's fine.
Here I have a solution using only LINQ functions:
// Record definition
class Record
{
public string Name;
public int Amount;
public Record(string name, int amount)
{
Name = name;
Amount = amount;
}
}
// actual code for setup and LINQ
List<Record> records = new List<Record>()
{
new Record("Laverne", 4),
new Record("Lenny", 2),
new Record("Shirley", 3),
new Record("Squiggy", 5)
};
int groupLimit = 10;
// the solution
List<Record[]> test =
records.GroupBy(record => records.TakeWhile(r => r != record)
.Concat(new[] { record })
.Sum(r => r.Amount) / (groupLimit + 1))
.Select(g => g.ToArray()).ToList();
This gives the correct result:
test =
{
{ [ "Laverne", 4 ], [ "Lenny", 2 ], [ "shirley", 3 ] },
{ [ "Squiggly", 5 ] }
}
The only downside is that this is O(n2). It essentially groups by the index of the group (as defined by using the sum of the record up to the current one). Note that groupLimit + 1 is needed so that we actually include groups from 0 to groupLimit, inclusive.
I'm trying to find a way of making it prettier, but it doesn't look easy.
A dotnet fiddle with a solution using Aggregate:
https://dotnetfiddle.net/gVgONH
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
// Record definition
public class Record
{
public string Name;
public int Amount;
public Record(string name, int amount)
{
Name = name;
Amount = amount;
}
}
public static void Main()
{
// actual code for setup and LINQ
List<Record> records = new List<Record>()
{
new Record("Alice", 1), new Record("Bob", 5), new Record("Charly", 4), new Record("Laverne", 4), new Record("Lenny", 2), new Record("Shirley", 3), new Record("Squiggy", 5)}
;
int groupLimit = 10;
int sum = 0;
var result = records.Aggregate(new List<List<Record>>(), (accumulated, next) =>
{
if ((sum + next.Amount >= groupLimit) || accumulated.Count() == 0)
{
Console.WriteLine("New team: " + accumulated.Count());
accumulated.Add(new List<Record>());
sum = 0;
}
sum += next.Amount;
Console.WriteLine("New member {0} ({1}): adds up to {2} ", next.Name, next.Amount, sum);
accumulated.Last().Add(next);
return accumulated;
}
);
Console.WriteLine("Team count: " + result.Count());
}
}
With output:
New team: 0
New member Alice (1): adds up to 1
New member Bob (5): adds up to 6
New team: 1
New member Charly (4): adds up to 4
New member Laverne (4): adds up to 8
New team: 2
New member Lenny (2): adds up to 2
New member Shirley (3): adds up to 5
New team: 3
New member Squiggy (5): adds up to 5
Team count: 4
There is no 'performant' way to do this with the built in Linq operators that I am aware of. You could create your own extension method, though:
public static class EnumerableExtensions
{
public static IEnumerable<TResult> GroupWhile<TSource, TAccumulation, TResult>(
this IEnumerable<TSource> source,
Func<TAccumulation> seedFactory,
Func<TAccumulation, TSource, TAccumulation> accumulator,
Func<TAccumulation, bool> predicate,
Func<TAccumulation, IEnumerable<TSource>, TResult> selector)
{
TAccumulation accumulation = seedFactory();
List<TSource> result = new List<TSource>();
using(IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while(enumerator.MoveNext())
{
if(!predicate(accumulator(accumulation, enumerator.Current)))
{
yield return selector(accumulation, result);
accumulation = seedFactory();
result = new List<TSource>();
}
result.Add(enumerator.Current);
accumulation = accumulator(accumulation, enumerator.Current);
}
if(result.Count > 0)
{
yield return selector(accumulation, result);
}
}
}
}
And then call it like this:
int limit = 10;
var groups =
records
.GroupWhile(
() => 0,
(a, x) => a + x,
(a) => a <= limit,
(a, g) => new { Total = a, Group = g });
The way it is currently written, if any single record exceeds that limit then that record is returned by itself. You could modify it to exclude records that exceed the limit or leave it as is and perform the exclusion with Where.
This solution has O(n) runtime.

How do I generate and print Fibonacci numbers in X10?

I would like to generate and print the first 10 Fibonacci numbers. I don't want to be efficient, but I want to see some (working) X10 code that is easy to understand.
My try
// file Fibonacci.x10
public class Fibonacci {
public static def fib(n:Int): Int {
if (n < 2) {
return n;
}
val f1:Int;
val f2:Int;
finish {
async f1 = fib(n-1);
async f2 = fib(n-2);
}
return f1 + f2;
}
public static def main(args:Rail[String]) {
x10.io.Console.OUT.println("This is fibonacci in X10.");
for (var i:Int=0; i < 10; ++i) {
x10.io.Console.OUT.println(i + ": " + fib(i));
fib(i);
}
}
}
When I compile this, I get:
/home/moose/Fibonacci.x10:11: No valid method call found for call in given type.
Call: fib(x10.lang.Long)
Type: Fibonacci
/home/moose/Fibonacci.x10:12: No valid method call found for call in given type.
Call: fib(x10.lang.Long)
Type: Fibonacci
/home/moose/Fibonacci.x10:19: Cannot assign expression to target; base types are incompatible.
Expression: 0L
Expected base type: x10.lang.Int
Found base type: x10.lang.Long
3 errors.
I use X10 release 2.4.2.
The following version works as expected:
// file Fibonacci.x10
public class Fibonacci {
public static def fib(n:Long): Long {
if (n < 2) {
return n;
}
val f1:Long;
val f2:Long;
finish {
async f1 = fib(n-1);
async f2 = fib(n-2);
}
return f1 + f2;
}
public static def main(args:Rail[String]) {
x10.io.Console.OUT.println("This is fibonacci in X10.");
for (var i:Long=0; i < 10; ++i) {
x10.io.Console.OUT.println(i + ": " + fib(i));
}
}
}
It seems as if number are Long per standard.

collection processing in BackgroundWorker

I try to make my ListBox connected to ObservaleCollection be more efficient so for the DB query I implemented a BackgroundWorker to do the job. Then whithin this backgroundworker I want to add every lets say 70 ms 3 entries to the UI, so the UI on larger number of entries (lets say 100) does not get blocked.
Here is the code:
void updateTMWorker_DoWork(object sender, DoWorkEventArgs e)
{
var MessagesInDB = from MessageViewModel tm in MessagesDB.Messages
where tm.Type.Equals(_type)
orderby tm.Distance
select tm;
// Execute the query and place the results into a collection.
Dispatcher.BeginInvoke(() => { MessagesClass.Instance.Messages = new ObservableCollection<MessageViewModel>(); });
Collection<MessageViewModel> tempM = new Collection<MessageViewModel>();
int tempCounter = 0;
foreach (MessageViewModel mToAdd in MessagesInDB)
{
if (MessagesClass.Instance.Messages.IndexOf(mToAdd) == -1)
{
tempM.Add(mToAdd);
tempCounter = tempCounter + 1;
}
if (tempCounter % 3 == 0)
{
tempCounter = 0;
Debug.WriteLine("SIZE OF TEMP:" + tempM.Count());
Dispatcher.BeginInvoke(() =>
{
// add 3 messages at once
MessagesClass.Instance.Messages.Add(tempM[0]);
MessagesClass.Instance.Messages.Add(tempM[1]);
MessagesClass.Instance.Messages.Add(tempM[2]);
});
tempM = new Collection<MessageViewModel>();
Thread.Sleep(70);
}
}
// finish off the rest
Dispatcher.BeginInvoke(() =>
{
for (int i = 0; i < tempM.Count(); i++)
{
MessagesClass.Instance.Messages.Add(tempM[i]);
}
});
}
The output is:
SIZE OF TEMP:3
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
in the line: MessagesClass.Instance.Messages.Add(tempM[0]); where the code tries to access the first element of tempM
Any hints whats wrong? Why can't I access the tempM elements, although the collection size is > 0?
You forget about thread synchronization. Look at your code:
1: Debug.WriteLine("SIZE OF TEMP:" + tempM.Count());
Dispatcher.BeginInvoke(() =>
{
// add 3 messages at once
3: MessagesClass.Instance.Messages.Add(tempM[0]);
MessagesClass.Instance.Messages.Add(tempM[1]);
MessagesClass.Instance.Messages.Add(tempM[2]);
});
2: tempM = new Collection<MessageViewModel>();
tempM already will be null when MessagesClass.Instance.Messages.Add(tempM[0]); is executed. So, use some sort or synchronization objects, for example:
EventWaitHandle Wait = new AutoResetEvent(false);
Debug.WriteLine("SIZE OF TEMP:" + tempM.Count());
Dispatcher.BeginInvoke(() =>
{
// add 3 messages at once
MessagesClass.Instance.Messages.Add(tempM[0]);
MessagesClass.Instance.Messages.Add(tempM[1]);
MessagesClass.Instance.Messages.Add(tempM[2]);
Wait.Set();
});
// wait while tempM is not in use anymore
Wait.WaitOne();
tempM = new Collection<MessageViewModel>();

Resources