New library user
-
Tuesday, October 02, 2012 7:56 PM
Hi All
Just started dipping my toes into TDF as part of a bit of research into the range of toolkits and approaches to concurrency in .NET these days. Looks very interesting indeed.
My first thoughts after seeing the introduction video were about using an ActionBlock as a thread safe function dispatcher, working with a non-thread safe third party library. I create an ActionBlock as so:
private ActionBlock<Action> ab = new ActionBlock<Action>(i => i());
ie, one that takes a delegate and executes it. I then make use of the action block as so:
ab.Post(() => libFunctionA(arg1, arg2, ar3));
ab.Post(() => libFunctionB());
ab.Post(() => libFunctionC(arg1, arg2));
The lambda function in the 'Post' captures the arguments, and so in this way I can cleanly and succinctly make calls to the library from any thread, knowing that they will be executed sequentially in a Thread Safe manner.
At the moment, the limitation to this is that some of the library functions return values that I need to use; this approach loses any returned values. I'm hoping that with some further reading I'll be able to make use of return values in a natural and easy to express way!
Anyway, just thought I'd share something that I thought was quite cool and very easy to use.
Cheers
Tom Davies
Tom Davies, Software Engineer, Solid State Logic
All Replies
-
Wednesday, October 03, 2012 9:59 AM
This way of using TDF will certainly work. But I can see some issues with it: there is no direct way of waiting until the operation actually executes and there is also no way of knowing whether the operation executed successfully.
Because of that, I think a better option would be to use async-await with something like AsyncLock:
private readonly AsyncLock m_lock = new AsyncLock(); async Task ExecuteSequentiallyAsync(Action action) { using (await m_lock.LockAsync()) { action(); } } async Task<T> ExecuteSequentiallyAsync<T>(Func<T> func) { using (await m_lock.LockAsync()) { return func(); } } … await ExecuteSequentiallyAsync(() => libFunctionA(arg1, arg2, ar3)); await ExecuteSequentiallyAsync(() => libFunctionB()); var resultC = await ExecuteSequentiallyAsync(() => libFunctionCThatReturnsSomething(arg1, arg2));This solves all of the issues in the original approach (await will asynchronously wait until the operation completes, it will rethrow any exceptions thrown during the operation and the operation can now also return some value) and the code is still thread-safe.
Another way to do this would be to execute the operations on the exclusive scheduler from ConcurrentExclusiveSchedulerPair:
var resultC = await Task.Factory.StartNew( () => libFunctionCThatReturnsSomething(arg1, arg2), CancellationToken.None, TaskCreationOptions.None, m_exclusiveScheduler);I think TDF is a great library, and can be sometimes useful even when you don't actually have some “dataflow”, but I think this is not one of those cases.
- Edited by svick Wednesday, October 03, 2012 10:01 AM
- Edited by svick Wednesday, October 03, 2012 10:03 AM
- Edited by svick Wednesday, October 03, 2012 10:04 AM
- Edited by svick Wednesday, October 03, 2012 10:04 AM
- Marked As Answer by thomashenrydavies Wednesday, October 03, 2012 2:54 PM
-
Wednesday, October 03, 2012 2:55 PMThat's a really excellent and helpful reply, many thanks.
Tom Davies, Software Engineer, Solid State Logic

