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();
}
}
Related
I am trying to ask a question with reference to the question Glib: Calling a iterative loop function
I am actually doing GStreamer and trying to use Glib library function in my application as much as possible. The program require some system event/response before performing some action in response to some user input
Design of flow
User input the option and application take it as user_input is asserted to be true
Application need install a callback (called it callback_A) -- which wait out for buffer flowing in that point of application
Callback-A will be called whenever buffer passes through a point.
In callback A, Application to wait for some particular condition (ie a key-frame buffer passing through) at a point. If a key frame buffer pass through, it will then install a second callback at some point downstream, callback-B. An EOS event is send out through the pipeline. Otherwise wait for next time a buffer pass through
In callback B, it will wait for the event (EOS) to arrive and determine further action. If everything is completed, set task_completed to be true
function return to main while loop. The blocking (task_completed) is released and the application will report the task completed to UI
Problem'
Currently I faced a problem of the callback not completing their task (takes a long time) before it went to being blocked by task completed (and being blocked thereafter)
Question
In Glib, is a callback within the same memory space(or thread) as its caller?
In Glib, how do I overcome the problem of being blocked? Is there some methods to ensure that the task are being run before time up and control is returned to the caller
Will a gthread help? Putting the two call-back as a separate thread since they need to wait for some events to happen
This may be too much. Any alternatives, example polling instead of callback in this case.
Code
Here is my pseudocode
gbool user_input;
gbool task_completed = false;
static void
callback_B(GstPad *pad,
GstPadProbeInfo *info,
gpointer udata)
{
//// wait for some events--- call it event B
GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
if (GST_EVENT_TYPE (event) != GST_EVENT_EOS)
return GST_PAD_PROBE_OK;
/// do something
/// ......
task_completed =true;
return GST_PAD_PROBE_REMOVE;
}
static void
callback_A( GstPad *pad,
GstBuffer * buffer,
gpointer udata)
{
//// wait for some event call it event A
if( !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT))
{
/// install callback-B to determine some condition
gst_pad_add_probe ( pad,
GST_PAD_PROBE_TYPE_BLOCK,
(GSourceFunc)callback_B,
//NULL,
NULL,
NULL);
GstPad* padB = gst_pad_get_peer (pad);
gst_pad_send_event(padB, gst_event_new_eos());
}
else
{
return GST_PAD_PROBE_REMOVE;
}
}
gboolean
check_cmd_session(NULL )
{
if(user_input)
{
// ........ some other actions *****************
/// initialize task_complete to be false
task_completed = false;
//// install callback_A
gst_pad_add_probe(padA,
GST_PAD_PROBE_TYPE_BUFFER,
callback_A,
NULL,
NULL);
while(!task_completed)
g_usleep(10000);
/// notify UI of changes done
notify_UI();
}
}
I have a method which creates an emitter like below, there are a problem(maybe it is normal behavior) with calling onError in retrofit callback. I got UndeliverableException when try to call onError.
I can solve this by checking subscriber.isDiposed() by I wonder how can call onError coz i need to notify my UI level.
Addition 1
--> RxJava2CallAdapterFactoryalready implemented
private static Retrofit.Builder builderSwift = new Retrofit.Builder()
.baseUrl(URL_SWIFT)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(new ToStringConverterFactory());
--> When i added below code to application class app won't crash
--> but i get java.lang.exception instead of my custom exception
RxJavaPlugins.setErrorHandler(Functions<Throwable>emptyConsumer());
#Override
public void onFileUploadError(Throwable e) {
Log.d(TAG, "onFileUploadError: " + e.getMessage());
}
public Observable<UploadResponseBean> upload(final UploadRequestBean uploadRequestBean, final File file) {
return Observable.create(new ObservableOnSubscribe<UploadResponseBean>() {
#Override
public void subscribe(#NonNull final ObservableEmitter<UploadResponseBean> subscriber) throws Exception {
// ---> There are no problem with subscriber while calling onError
// ---> Retrofit2 service request
ftsService.upload(token, uploadRequestBean, body).enqueue(new Callback<UploadResponseBean>() {
#Override
public void onResponse(Call<UploadResponseBean> call, Response<UploadResponseBean> response) {
if (response.code() == 200){
// ---> calling onNext works properly
subscriber.onNext(new UploadResponseBean(response.body().getUrl()));
}
else{
// ---> calling onError throws UndeliverableException
subscriber.onError(new NetworkConnectionException(response.message()));
}
}
#Override
public void onFailure(Call call, Throwable t) {
subscriber.onError(new NetworkConnectionException(t.getMessage()));
}
});
}
});
}
Since version 2.1.1 tryOnError is available:
The emitter API (such as FlowableEmitter, SingleEmitter, etc.) now
features a new method, tryOnError that tries to emit the Throwable if
the sequence is not cancelled/disposed. Unlike the regular onError, if
the downstream is no longer willing to accept events, the method
returns false and doesn't signal an UndeliverableException.
https://github.com/ReactiveX/RxJava/blob/2.x/CHANGES.md
The problem is like you say you need to check if Subscriber is already disposed, that's because RxJava2 is more strict regarding errors that been thrown after Subscriber already disposed.
RxJava2 deliver this kind of error to RxJavaPlugins.onError that by default print to stack trace and calls to thread uncaught exception handler. you can read full explanation here.
Now what's happens here, is that you probably unsubscribed (dispose) from this Observable before query was done and error delivered and as such - you get the UndeliverableException.
I wonder how can call onError coz i need to notify my UI level.
as this is happened after your UI been unsubscribed the UI shouldn't care. in normal flow this error should delivered properly.
Some general points regarding your implementation:
the same issue will happen at the onError in case you've been unsubscribed before.
there is no cancellation logic here (that's what causing this problem) so request continue even if Subscriber unsubscribed.
even if you'll implement this logic (using ObservableEmitter.setCancellable() / setDisposable()) you will still encounter this problem in case you will unsubscribe before request is done - this will cause cancellation and your onFailure logic will call onError() and the same issue will happen.
as you performing an async call via Retrofit the specified subscription Scheduler will not make the actual request happen on the Scheduler thread but just the subscription. you can use Observable.fromCallable and Retrofit blocking call execute to gain more control over the actual thread call is happened.
to sum it up -
guarding calls to onError() with ObservableEmitter.isDiposed() is a good practice in this case.
But I think the best practice is to use Retrofit RxJava call adapter, so you'll get wrapped Observable that doing the Retrofit call and already have all this considerations.
I found out that this issue was caused by using incorrect context when retrieving view model in Fragment:
ViewModelProviders.of(requireActivity(), myViewModelFactory).get(MyViewModel.class);
Because of this, the view model lived in context of activity instead of fragment. Changing it to following code fixed the problem.
ViewModelProviders.of(this, myViewModelFactory).get(MyViewModel.class);
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 am new to multithreading in Android and I have a doubt. I have a AsyncTask instance which I call as BackGroundTask and I start this as:
BackGroundTask bgTask = new BackGroundTask();
bgTask.execute();
However I would like to wait until this call is finished its execution, before proceeding to the other statements of code without blocking UI thread and allowing user to navigate through application.
Please help me so that I can achieve this.
put your code inside onPostExecute method of AsyncTask, which you
wants to execute after work done By worker thread.
Try using bgTask.execute().get() this will wait for the background task to finish before moving to the next instruction in the called thread. (Please note that this will block the called thread until background task finishes)
I have found the answer at
How do I retrieve the data from AsyncTasks doInBackground()?
And the answer is to use callback as shown below which is copied from above shared link:
The only way to do this is using a CallBack. You can do something like this:
new CallServiceTask(this).execute(request, url);
Then in your CallServiceTask add a local class variable and class a method from that class in your onPostExecute:
private class CallServiceTask extends AsyncTask<Object, Void, Object[]>
{
RestClient caller;
CallServiceTask(RestClient caller) {
this.caller = caller;
}
protected Object[] doInBackground(Object... params)
{
HttpUriRequest req = (HttpUriRequest) params[0];
String url = (String) params[1];
return executeRequest(req, url);
}
protected onPostExecute(Object result) {
caller.onBackgroundTaskCompleted(result);
}
}
Then simply use the Object as you like in the onBackgroundTaskCompleted() method in your RestClient class.
A more elegant and extendible solution would be to use interfaces. For an example implementation see this library. I've just started it but it has an example of what you want.
I'm writing a small programm where JavaFx acts as a viewer and controler and let Java do the other hard work. I can start multiple threads from Javafx however, I'm not able to stop them. If I try to use .stop(), the threads are still running.
Here is one of them:
public var sleepTask_connect;
function LogOutAction(): Void {
sleepTask_connect.stop();
}
function LogInAction(): Void {
var listener = FXListener_interface_connection {
override function callback(errorCode, errorMessage): Void {
//do something
if(errorCode != 200){
setIcn(errorMessage);
}
}
}
sleepTask_connect = FXListener_connection {
listener: listener
};
sleepTask_connect.start();
}
Use JavaTaskBase to implement you Java thread. There is a stop method to kill the thread. Here is an example of how you use it.
I've had better luck with the JFXtras XWorker component for threading. See http://jfxtras.googlecode.com/svn/site/javadoc/release-0.6/org.jfxtras.async/org.jfxtras.async.XWorker.html.
However in general in order for your thread to respond to cancel/stop requests, you have to check the canceled or stopped flag in your code during your "do something" section. This works if your thread is in an infinite loop for example, or if you just have a series of long running processes you can check for canceled/stopped in between them. Alternatively, if your code calls some blocking method (like sockets or a blocking queue), then most of these will throw an InterruptedException when the thread is canceled.