In DBFlow's docs you can read that:
While generally saving data synchronous should be avoided, for small
amounts of data it has little effect.
That's great! ...But, on the other hand there's this notice:
Doing operations on the main thread can block it if you read and write
to the DB on a different thread while accessing DB on the main.
So if I understand this correctly, if I have for example android service that periodically reads/writes to db using async transactions (in separate thread) and user clicks a button in Activity that executes simple model.save() then the main thread of my android application would be blocked and app would 'freeze' until db is unlocked.
Is that right?
If it is, the solution could be to place all db calls on async thread's queue, like:
interface AsyncResult {
fun onResult(success: Boolean)
}
fun MyModel.save(callback: AsyncResult) {
database<AppDatabase>().beginTransactionAsync { this.save() }
.success { callback.onResult(true) }
.error { _, _ -> callback.onResult(false)}
.build()
.execute()
}
and exeute it from Activity like:
myModel.save(object: AsyncResult {
override fun onResult(success: Boolean) = if (success) showToast("got it")
})
But aren't the simple calls like save(), insert() wrapped in implicit transactions, so we end up with nested transactions?
Not to mention all the boilerplate code on the model and view layers.
What is the proper way to deal with such a problem?
Related
In my Android application I have code that should run periodically in its own coroutine and should be cancelable.
for this I have the following functions:
startJob(): Initializes the job, sets up invokeOnCompletion() and starts the work loop in the respective scope
private fun startJob() {
if (::myJob.isInitialized && myJob.isActive) {
return
}
myJob= Job()
myJob.invokeOnCompletion {
it?.message.let {
var msg = it
if (msg.isNullOrBlank()) {
msg = "Job stopped. Reason unknown"
}
myJobCompleted(msg)
}
}
CoroutineScope(Dispatchers.IO + myJob).launch {
workloop()
}
}
workloop(): The main work loop. Do some work in a loop with a set delay in each iteration:
private suspend fun workloop() {
while (true) {
// doing some stuff here
delay(setDelayInMilliseconds)
}
}
myJobCompleted: do some finalizing. For now simply log a message for testing.
private fun myJobCompleted(msg: String) {
try {
mainActivityReference.logToGUI(msg)
}
catch (e:Exception){
println("debug: " + e.message)
}
}
Running this and calling myJob.Cancel() will throw the following exception in myJobCompleted():
debug: Only the original thread that created a view hierarchy can touch its views.
I'm curious as to why this code isn't running on the main thread, since startJob() IS called from the main thread?
Furthermore: is there a option similar to using a CancellationTokenSource in c#, where the job is not immediately cancelled, but a cancellation request can be checked each iteration of the while loop?
Immediately breaking off the job, regardless of what it is doing (although it will pretty much always be waiting for the delay on cancellation) doesn't seem like a good idea to me.
It is not the contract of Job.invokeOnCompletion to run on the same thread where Job is created. Moreover, such a contract would be impossible to implement.
You can't expect an arbitrary piece of code to run on an arbitrary thread, just because there was some earlier method invocation on that thread. The ability of the Android main GUI thread to execute code submitted from the outside is special, and involves the existence a top-level event loop.
In the world of coroutines, what controls thread assignment is the coroutine context, while clearly you are outside of any context when creating the job. So the way to fix it is to explicitly launch(Dispatchers.Main) a coroutine from within invokeOnCompletion.
About you question on cancellation, you can use withContext(NonCancellable) to surround the part of code you want to protect from cancellation.
I'm creating a networked game in Unity using tcp based sockets.
(I'm new to networking and threading stuff).
I'm using System.Net.Sockets async methods like socket.BeginReceive() and socket.EndReceive().
All the client-server connecting and messaging works. But as soon as I try access anything from a Monobehavior (so that I can actually have any effect on the Unity game), like a gameobject's transform, an exception is thrown telling me that I can only access these properties from the main thread.
My question is: why am I not back on the main thread in the callback to foo.beginRecieve(), or at least after I call foo.EndReceive()? How do I return to the main thread using the async socket api? Will I end up having to use the synchronous socket api and just handle the threading myself so I can properly resync with Unity's main thread?
Thanks!
Any help would be much appreciated.
//code which sets up the callbacks which are executed when a client receives a message from the server
void BeginReceive() => _clientSocket.BeginReceive(_messageReceivedBuffer, 0, _messageReceivedBuffer.Length, SocketFlags.None, ReceiveCallback, null);
void ReceiveCallback(IAsyncResult result)
{
_clientSocket.EndReceive(result);
var msg = _serializer.ByteArrayToObject<NetworkMessage>(_messageReceivedBuffer);
//this clientmanipulation manipulates the game grid and the gameobjects' which it references
//it's in this method that an exception gets thrown and the code breaks
msg.ClientManipulation(_gameGrid);
BeginReceive();
}
In general for EndReceive:
Before calling BeginReceive, you need to create a callback method that implements the AsyncCallback delegate. This callback method executes in a separate thread and is called by the system after BeginReceive returns. The callback method must accept the IAsyncResult returned by the BeginReceive method as a parameter.
[...]
The EndReceive method will block until data is available.
Usually you would use a pattern often referred to as Main Thread Dispatcher using a ConcurrentQueue. For Unity this is quite easy since you already have something that is surely always been executed in the main thread: Update
public class Example : MonoBehaviour
{
...
private ConcurrentQueue<Action> _mainThreadActions = new ConcurrentQueue<Action>();
private void Update()
{
// Handle all callbacks in main thread
while(_mainthreadActions.Count > 0 && _mainThreadActions.TryDequeue(out var action))
{
action?.Invoke();
}
}
void BeginReceive()
{
_clientSocket.BeginReceive(_messageReceivedBuffer, 0, _messageReceivedBuffer.Length, SocketFlags.None, ReceiveCallback, null);
}
void ReceiveCallback(IAsyncResult result)
{
_clientSocket.EndReceive(result);
var msg = _serializer.ByteArrayToObject<NetworkMessage>(_messageReceivedBuffer);
// On threads / possibly async code enqueue the action to be invoked in the main thread
_mainThreadActions.Enqueue(()=> {msg.ClientManipulation(_gameGrid)});
BeginReceive();
}
}
I'm having trouble understanding how to create a synchronous NSOperationQueue.
I've created a prototype that basically says:
Create 4 operations that very long or very short to complete
Regardless of time to complete, they should finish in the order they are created in the queue.
My NSOperation class is very simple:
class LGOperation : NSOperation
{
private var operation: () -> ()
init(operation: () -> ())
{
self.operation = operation
}
override func main()
{
if self.cancelled {
return
}
operation()
}
}
And my test class is also quite simple:
class LGOperationTest
{
class func downloadImage(url: String)
{
// This is a simple AFHTTPRequestOperation for the image
LGImageHelper.downloadImageWithUrl(url, complete: { (image: AnyObject?) in
println("downloaded \(url)")
})
}
class func test()
{
var queue = NSOperationQueue.mainQueue()
queue.maxConcurrentOperationCount = 1
var op1 = LGOperation(operation: { self.downloadImage("http://www.toysrus.com/graphics/tru_prod_images/Animal-Planet-T-Rex---Grey--pTRU1-2909995dt.jpg") })
var op2 = LGOperation(operation: { println("OPERATION 2") })
var op3 = LGOperation(operation: { self.downloadImage("http://www.badassoftheweek.com/trex.jpg") })
var op4 = LGOperation(operation: { println("OPERATION 3") })
var ops: [NSOperation] = [op1, op2, op3, op4]
op2.addDependency(op1)
op3.addDependency(op2)
op4.addDependency(op3)
op4.completionBlock = {
println("finished op 4")
}
queue.addOperation(op1)
queue.addOperation(op2)
queue.addOperation(op3)
queue.addOperation(op4)
println("DONE")
}
}
So I would expect here is for the operations to finish in order, instead the output is:
DONE
OPERATION 2
OPERATION 4
finished op 4
downloaded
http://www.toysrus.com/graphics/tru_prod_images/Animal-Planet-T-Rex---Grey--pTRU1-2909995dt.jpg
downloaded http://www.badassoftheweek.com/trex.jpg
WHY can't I make web requests fire synchronously with other code? (I know I can use completion blocks and chain them but I'd like to figure out how to do it with NSOperation)
Operation queues are used to schedule asynchronous operations, primarily these operations may be long running and you don't want to block the current (typically UI) thread. Blocking the UI thread leads to unresponsive UI.
When you create 4 operations, when they finish is a factor of what is being performed. In your case, you have operations that are doing println (which is very fast) and you have operations that are downloading from the internet (which is very slow).
The whole point of the operation queue is to allow you to fire these operations asynchronously, and whenever the operations complete, fire the completion handler.
In other words, you do cannot control the sequence.
If you want to control the sequence, my suggestion is to do the following:
Start operation 1
In operation 1's completion handler, start operation 2
In operation 2's completion handler, start operation 3
In operation 3's completion handler, start operation 4
In this way, you still achieve the benefits of Operation queues (you do not block the UI thread), and you can chain the operations in order.
I have an issue with cross threading on a UI. I have read all the ways to do it and have implemented them as seen below.
public void UpdateList(object obj)
{
// do we need to switch threads?
if (listBox1.InvokeRequired)
{
MethodInvoker del = () => UpdateList(obj);
this.Invoke(del);
return;
}
// ok so now we're here, this means we're able to update the control
// so we unbox the object into a string
string text = (string)obj;
// and update
listBox1.Items.Add(text);
}
The issue comes when I try to do a
hubConnection.Start().Wait();
After that call I am trying to update my list.
Without the wait is fine. When I add the Wait it hangs on the UpdateList Invoke. There is no error...it just hangs.
I am handling this call in a button event.
Wait() is creating a deadlock on the mainthread.
Replace the hubconnection.Start.Wait() with:
await hubconnection.Start() in an async method:
public void async StartHubClickedEvent(...){
await hubconnection.Start()
}
The Microsoft Async library enables use of async/awaut on .net 4.0 and VS12.
Install-Package Microsoft.Bcl.Async
See Deadlock when thread uses dispatcher and the main thread is waiting for thread to finish
You've generated a recursive loop. Assuming an Invoke is Required, you'll call up the same method, hit if (listBox1.InvokeRequired) again (which will still pass true) and start looping as you keep calling up the same method again and again. It's better to do an If..Else pattern here where you directly invoke the change on the ListBox or simply perform the change without the invoke
An Example
if (listBox1.InvokeRequired)
{
listBox1.Invoke(()=> { listBox1.Items.Add((string)text) };
}
else
{
string text = (string)obj;
// and update
listBox1.Items.Add(text);
}
I'm implementing my own logging framework. Following is my BaseLogger which receives the log entries and push it to the actual Logger which implements the abstract Log method.
I use the C# TPL for logging in an Async manner. I use Threads instead of TPL. (TPL task doesn't hold a real thread. So if all threads of the application end, tasks will stop as well, which will cause all 'waiting' log entries to be lost.)
public abstract class BaseLogger
{
// ... Omitted properties constructor .etc. ... //
public virtual void AddLogEntry(LogEntry entry)
{
if (!AsyncSupported)
{
// the underlying logger doesn't support Async.
// Simply call the log method and return.
Log(entry);
return;
}
// Logger supports Async.
LogAsync(entry);
}
private void LogAsync(LogEntry entry)
{
lock (LogQueueSyncRoot) // Make sure we ave a lock before accessing the queue.
{
LogQueue.Enqueue(entry);
}
if (LogThread == null || LogThread.ThreadState == ThreadState.Stopped)
{ // either the thread is completed, or this is the first time we're logging to this logger.
LogTask = new new Thread(new ThreadStart(() =>
{
while (true)
{
LogEntry logEntry;
lock (LogQueueSyncRoot)
{
if (LogQueue.Count > 0)
{
logEntry = LogQueue.Dequeue();
}
else
{
break;
// is it possible for a message to be added,
// right after the break and I leanve the lock {} but
// before I exit the loop and task gets 'completed' ??
}
}
Log(logEntry);
}
}));
LogThread.Start();
}
}
// Actual logger implimentations will impliment this method.
protected abstract void Log(LogEntry entry);
}
Note that AddLogEntry can be called from multiple threads at the same time.
My question is, is it possible for this implementation to lose log entries ?
I'm worried that, is it possible to add a log entry to the queue, right after my thread exists the loop with the break statement and exits the lock block, and which is in the else clause, and the thread is still in the 'Running' state.
I do realize that, because I'm using a queue, even if I miss an entry, the next request to log, will push the missed entry as well. But this is not acceptable, specially if this happens for the last log entry of the application.
Also, please let me know whether and how I can implement the same, but using the new C# 5.0 async and await keywords with a cleaner code. I don't mind requiring .NET 4.5.
Thanks in Advance.
While you could likely get this to work, in my experience, I'd recommend, if possible, use an existing logging framework :) For instance, there are various options for async logging/appenders with log4net, such as this async appender wrapper thingy.
Otherwise, IMHO since you're going to be blocking a threadpool thread during your logging operation anyway, I would instead just start a dedicated thread for your logging. You seem to be kind-of going for that approach already, just via Task so that you'd not hold a threadpool thread when nothing is logging. However, the simplification in implementation I think benefits just having the dedicated thread.
Once you have a dedicated logging thread, you then only need have an intermediate ConcurrentQueue. At that point, your log method just adds to the queue and your dedicated logging thread just does that while loop you already have. You can wrap with BlockingCollection if you need blocking/bounded behavior.
By having the dedicated thread as the only thing that writes, it eliminates any possibility of having multiple threads/tasks pulling off queue entries and trying to write log entries at the same time (painful race condition). Since the log method is now just adding to a collection, it doesn't need to be async and you don't need to deal with the TPL at all, making it simpler and easier to reason about (and hopefully in the category of 'obviously correct' or thereabouts :)
This 'dedicated logging thread' approach is what I believe the log4net appender I linked to does as well, FWIW, in case that helps serve as an example.
I see two race conditions off the top of my head:
You can spin up more than one Thread if multiple threads call AddLogEntry. This won't cause lost events but is inefficient.
Yes, an event can be queued while the Thread is exiting, and in that case it would be "lost".
Also, there's a serious performance issue here: unless you're logging constantly (thousands of times a second), you're going to be spinning up a new Thread for each log entry. That will get expensive quickly.
Like James, I agree that you should use an established logging library. Logging is not as trivial as it seems, and there are already many solutions.
That said, if you want a nice .NET 4.5-based approach, it's pretty easy:
public abstract class BaseLogger
{
private readonly ActionBlock<LogEntry> block;
protected BaseLogger(int maxDegreeOfParallelism = 1)
{
block = new ActionBlock<LogEntry>(
entry =>
{
Log(entry);
},
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism,
});
}
public virtual void AddLogEntry(LogEntry entry)
{
block.Post(entry);
}
protected abstract void Log(LogEntry entry);
}
Regarding the loosing waiting messages on app crush because of unhandled exception, I've bound a handler to the event AppDomain.CurrentDomain.DomainUnload. Goes like this:
protected ManualResetEvent flushing = new ManualResetEvent(true);
protected AsyncLogger() // ctor of logger
{
AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload;
}
protected void CurrentDomain_DomainUnload(object sender, EventArgs e)
{
if (!IsEmpty)
{
flushing.WaitOne();
}
}
Maybe not too clean, but works.