We are building a content editor that brings up a "cocos Player" in an NSWindow for test purposes. The user can test some content and then close the window.
So I need to be able to shutdown cocos and re-start within the same app.
Everything is working if I use the CC_MAC_USE_DISPLAY_LINK_THREAD threading model. I had to make a fix in CCDirectorMac to get this working. In CCDirectorMac | stopAnimation I had to set the _runningThread to nil since it is not set to nil by the #if and #elif when using CC_MAC_USE_DISPLAY_LINK_THREAD.
Anyway so now I am able to "end" a director and then re-start it later with no issues.
My question though is this: If I am building an AppKit editor with occasional use of cocos2D whould my threading model really be CC_MAC_USE_MAIN_THREAD as is suggested in the documentation?
When I do use CC_MAC_USE_MAIN_THREAD I get a HANG in in stopAnimation on the line:
CVDisplayLinkStop(displayLink);
I think the main thread would be fine and would avoid threading issues for our tool. Performance is not a concern. I can't find any sample code that shuts down and restarts cocos2d in an NSWindow ... so my assumption here is that I am in untested waters (or little tested waters).
My steps to shutdown/restart are:
Call [[CCDirector sharedDirector] end]
This calls stopAnimation
Then re-initialize cocos2d the same way I did originally
Any advice on threading models for a Mac desktop app ... and why CVDisplayLinkStop hangs would be greatly appreciated.
Thanks in advance.
Ok, I figured it out after reading this post and its answers on the Apple mailing list: http://lists.apple.com/archives/quartz-dev/2006/Oct/msg00056.html
When using CC_MAC_USE_MAIN_THREAD, the display link thread uses performSelector:onThread:waitUntilDone: to run drawScene: on the main thread. It passes YES for the waitUntilDone: parameter, so the display link thread blocks until the main thread can process the drawScene: call.
Here's the relevant fragment of the cocos2d code. MyDisplayLinkCallback is called on the display link thread.
static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
CVReturn result = [(CCDirectorDisplayLink*)displayLinkContext getFrameForTime:outputTime];
return result;
}
- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime
{
#if (CC_DIRECTOR_MAC_THREAD == CC_MAC_USE_DISPLAY_LINK_THREAD)
...
#else
// Display link thread blocks here:
[self performSelector:#selector(drawScene) onThread:_runningThread withObject:nil waitUntilDone:YES];
#endif
return kCVReturnSuccess;
}
The problem appears when the main thread tries to run CVDisplayLinkStop() which blocks until the display link callback in the display link thread finishes. Since the callback is at the same time waiting for the main thread to process its drawScene: call, both threads become deadlocked.
- (void) stopAnimation
{
...
if( displayLink ) {
// Main thread blocks here:
CVDisplayLinkStop(displayLink);
...
}
So, now for my workaround. I added a line to run the main thread's runloop in order to force the drawScene: call to be executed, which unblocks the display link thread. That way, when you call CVDisplayLinkStop() you're safe. Here's my addition (CCDirectorMac.m line 473 in cocos2d 2.1 release):
- (void) stopAnimation
{
...
if( displayLink ) {
#if (CC_DIRECTOR_MAC_THREAD != CC_MAC_USE_DISPLAY_LINK_THREAD)
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
#endif
CVDisplayLinkStop(displayLink);
...
}
I'm not sure this is the right thing to do, there's probably a better way to deal with this, but this workaround is good enough for me at the moment.
Thanks for this post, it helped me figure out how to solve the same deadlock, in a non-cocos2d app, by processing the display link callback on a separate thread, never on the main thread.
static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime,
CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void *userInfo)
{
static dispatch_queue_t sDisplayQueue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sDisplayQueue = dispatch_queue_create("com.company.app.displayLink", NULL);
});
dispatch_sync(sDisplayQueue, ^{
<stuff>
});
return kCVReturnSuccess;
}
Related
Currently, in my project, we are using gtkmm pixbuf create_from_file or create_from_date which hangs up whole GUI for 1-2 seconds in case of high-resolution images and in case of loading multiple images for a screen it becomes awfully slow. Is it possible to load images asynchronously in gtkmm for the above two functions? I am able to find methods in gtk for loading images asynchronously but not in gtkmm. An example would be helpful since I am unable to find anything related to it.
if(!imageName.empty())
{
//Load image in pixbuf
picPixBuff = Gdk::Pixbuf::create_from_file(imageName);
picPixBuff = picPixBuff->scale_simple(150,35,Gdk::INTERP_BILINEAR);
}
I have gone through this.
Related Question - How to load a widget as a different thread in gtk? (vala)
There are docs for that. That example does exactly what you are asking for.
These are the functions that do the magic. The example is easy to follow.
// notify() is called from ExampleWorker::do_work(). It is executed in the worker
// thread. It triggers a call to on_notification_from_worker_thread(), which is
// executed in the GUI thread.
void ExampleWindow::notify()
{
m_Dispatcher.emit();
}
void ExampleWindow::on_notification_from_worker_thread()
{
if (m_WorkerThread && m_Worker.has_stopped())
{
// Work is done.
if (m_WorkerThread->joinable())
m_WorkerThread->join();
delete m_WorkerThread;
m_WorkerThread = nullptr;
update_start_stop_buttons();
}
update_widgets();
}
I'm trying to write a multithreaded graphics manipulation program using Borland's C++ Builder 6 on WinXP SP3, but have run into (I think) a synchronisation issue, and can't figure out why.
Main Form (Form1) has a TPicture loaded from file. A copy of this is acquired by the thread via a Synchronize() call, and works fine. The thread does some work on the image, and in theory, it periodically updates the main Form image. The main Form also controls a machine, and is a 'First Resort' emergency stop, so blocking isn't an option. Everything is fine until the main Form gets hold of the working copy, or a copy of the working copy (sorry, but it's got to that) at which point the program hangs, and is only responsive to a 'program reset' from the IDE. A poor solution is to copy the working image to the Clipboard, and then, from the main Form, copy from the Clipboard to the main Form's image.
//Synchronization routines:
//----------------------------------------------------------------
`void __fastcall ImageRout::update()
{
Form1->Image9->Picture->Bitmap->Assign(Imgcopy);
//never returns
}
//----------------------------------------------------------------
void __fastcall ImageRout::getimage()
{
Imgcopy->Assign(Form1->Image9->Picture);
}
//----------------------------------------------------------------
//do the initialisation things... Then,
//(data is a struct, loaded with image data via a Synchronize() call)
Imgcopy=new Graphics::TBitmap;
Imgcopy->Width=data.width;
Imgcopy->Height=data.height; //size the bitmap
while(Imgcopy->Canvas->LockCount!=1)
{
Imgcopy->Canvas->TryLock();
} //have to Lock() the image or it gets lost... Somewhere
Synchronize(getimage); //works fine
//do some work on Imgcopy
//"By the book"- attempt 1
//(rate (=15) is a 'brake' to stop every alteration being displayed)
update_count++;
if(update_count>rate) //after a few iterations, update
{ //user interface
Synchronize(update); //fails: never returns from Synchronize call
update_count=0;
}
After a lot of failed attempts, I came up with this.
//in the thread...
update_count++;
if(update_count>rate)
{
EnterCriticalSection(&Form1->mylock1);
Form1->tempimage->Assign(Imgcopy); //tempimage is another bitmap,
InterlockedExchange(&Form1->imageready,1);//declared in the main Form
LeaveCriticalSection(&Form1->mylock1); //and is only ever accessed
update_count=0; //inside a critical section
}
//...and in the main Form....
if(imageready==1)
{
EnterCriticalSection(&mylock1);
Image9->Picture->Bitmap->Assign(tempimage); //Fails here
InterlockedExchange(&gotimage,1);
InterlockedExchange(&imageready,0);
LeaveCriticalSection(&mylock1);
}
So, in desperation.
//in the thread...
update_count++;
if(update_count>rate)
{
Synchronize(update);
EnterCriticalSection(&Form1->mylock1);
Form1->tempimage->Assign(Imgcopy);
Clipboard()->Assign(Imgcopy);
InterlockedExchange(&Form1->imageready,1);
LeaveCriticalSection(&Form1->mylock1); */
update_count=0;
}
//and in the main Form...
if(imageready==1)
{
EnterCriticalSection(&mylock1);
if (Clipboard()->HasFormat(CF_BITMAP))
{
Image9->Picture->Bitmap->Assign(Clipboard());
}
InterlockedExchange(&gotimage,1);
InterlockedExchange(&imageready,0);
LeaveCriticalSection(&mylock1);
}
This last attempt works, albeit relatively slowly, because of the Clipboard overhead, and it's a poor crutch, at best. I suspect the Clipboard is enforcing an otherwise failed synchronisation effort, but, as I said earlier, I can't fathom why. What can be the issue?
Thanks for your comments, Remy. They shook me out of a "tizzy" I'd got myself into whilst trying to solve the problem. I'd forgotten that Windows needs to move memory blocks around, and can't do this if locked them.
The initial problem of the Synchronize(update) call (code block 1 above) was caused by my still having the working copy (Imgcopy) locked (from inside the thread) during the call, preventing the main Form from subsequently accessing it. I suspect (but haven't investigated- that code has gone) the same root cause was at work in code block 2.
Locking every bitmap just prior to access, and unlocking immediately afterwards has solved this problem.
Peter O, thanks for your edit- I didn't realise there was so much overhead in my initial post.
As I understood, I'm doing it that way:
My main function launch some threads before entering into the gtk main loop.
boost::thread p4(sensors_get_informations);
gtk_main ();
Thoses threads do some stuff, and then update the corresponding element in the interface.
void sensors_get_informations()
{
while(!quit)
{
[...] //Doing some stuff
gdk_threads_add_idle((GSourceFunc)update_label_sensors, &str_end); //Here the interface will be updated
wait(1000);
}
}
And the function wich will update the element (here it's a label)
static bool update_label_sensors(....)
{
[...]
gtk_label_set_label(GTK_LABEL(label_sensors), label_string);
[...]
return false;
}
I have currently 5 threads working together, and it seems to work fine, but is this the usual way to do this, or is there a way to improve it ?
Here someone present an other method to update something on the interface, but with some research it appears that updating widget from other threads than the main GTK thread sometime cause segmentation fault.
This is the usual way to do it. Updating widgets from other threads than the main GTK thread is not allowed and will cause your program to crash unpredictably.
Problem Description
I have a function StdString ShowLockScreen() in this function I call activateViewController function which shows some UI where user must enter PIN, just after calling activateViewController function I want to lock all processes until user will enter his PIN and press OK button on opened UI. Below you can see code which I try
Source code in iOS
StdString ShowLockScreen()
{
// Create a lock.
NSLock* theLock = [[NSLock alloc] init];
// Create a UI in which user must enter his PIN.
PinLockController* controller = [[PinLockController alloc] initWithStyle:PinLockTypeSet];
// Set delegate.
controller.delegate = m_Context;
// !!! Here I show a UI and just after that I lock my lock in order code stop executing there.
[controller activateViewController:nil];
#synchronized(theLock) {
[theLock lock];
}
NSLog(#"User in UI unlock the lock");
}
I want that my code stops then I call [theLock lock]; and after I will call [theLock unlock]; from my UI and code will continue executing. But it doesn't work in my case.
Source code in Android
I have write similar application in Android and here is code. I want to write same in iOS but I can;t find solution
Intent intent = new Intent(mCtx, SoftPinActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SharedObject lock = new SharedObject("");
int lockId = SharedObject.acquireLockId(lock);
Logger.i(TAG, "lockId = " + lockId);
intent.putExtra(SharedObject.LOCK_ID, lockId);
intent.putExtra(SoftPinActivity.UI_ID, style);
synchronized (lock) {
mCtx.startActivity(intent);
try {
Logger.i(TAG, "lock.wait()...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
Logger.i(TAG, "InterruptedException");
}
}
Logger.i(TAG, "lock.wait()...done");
SharedObject.releaseLockId(lockId);
String pin = lock.object();
Researches
I think I must use
NSCondition* condLock = [[NSCondition alloc] init];
[condLock wait];
and
[condLock signal];
but how to use this in my code ?
Answer to problem
You can lock threads using NSLock, but in your situation, this doesn't seem to be applicable. The reason being is that locking is primarily used to provide thread safety when data is accessed from multiple threads. What you're asking for is a domain level lock, which prevents the user from using the application unless they've typed in their PIN. These two concepts share the word "lock", but they're entirely different in their implementation. If you were to use NSLock and its related counterparts, you're forcing your implementation into separate threads purely to block user interaction, and risk complicating your project and pains in debugging (deadlocks much?).
Suggested solution
As the concept is a domain level locking mechanism, I suggest we keep it this way for its implementation. If you want it to be analogous to Android, then you'd need to create your own concept of a 'SharedObject' that everything else queries. If this object were to say "The user hasn't unlocked the application", then nothing will process. This keeps you away from manually managing threads, and frees threads up for when you really need them most (asynchronous processing for example).
To implement this object, lets call it a UserContext, which is available as a singleton. How to implement this sharedInstance can be seen here.
Once you have that, then you can add various properties to it that are global throughout the application (and by the suggestion of the name, has all global properties that belong to a particular user). One of these properties is whether the user has the app locked or not:
[[UserContext sharedInstance] isLocked] // Returns BOOL
Using this throughout your application, you can then control (at the domain concept level), whether a method can compute something or not (naturally, you'll need to make UserContext thread safe, as it could be queried anywhere at any time). It would make it clear to the developer reading the code, that a certain method can not do anything unless the user has unlocked the app. To stop
Side notes
I want that my code stops then I call [theLock lock]; and after I will call [theLock unlock]; from my UI and code will continue executing.
Do not, under any circumstances, lock the UI thread. In a published app, the watchdog will kill your app, and it will effectively crash.
ViTo, as much I concerned with the NSLock, we use it in the case of multi-threading in which we lock a particular thread and force that upto that not unlock, none other thread become active or to do his required task.
So, may be what we can do that first of all we start all of your processes in the terms of thread and at that point when you try to open your UI we call 'lock' and when user pressed the button after inputting the text-box then we call 'unlock'.
But, for this we've to sure that this thread has high priority.
That's what I'm thinking right now, but really try this with my sample code and will update you accordingly.
Check that part of code:
+(void)aMethod:(id)param{
int x;
for(x=0;x<50;++x)
{enter code here
[lock lock];
printf("Object Thread says x is %i\n",x);
usleep(1);
[lock unlock];
}
}
- (void)viewDidLoad
{
int x;
lock = [[NSLock alloc] init];
[NSThread detachNewThreadSelector:#selector(aMethod:) toTarget:[MViewController class] withObject:nil];
for(x=0;x<50;++x)
{
[lock lock];
printf("Main thread says x is %i\n",x);
usleep(10000);
printf("Main thread lets go %i\n",x);
[lock unlock];
usleep(100);
}
printf("Now getting the process");
[super viewDidLoad];
}
Check the log you'll get what you want.
Hope, it's what you need. For any concern, shout-over me.
Okay I found solution to this issue, below you can see implemented function and line by line description.
StdString ShowLockScreen()
{
// Create NSCondition lock object.
NSCondition* conditionLock = [[NSCondition alloc] init];
// Here I create my UI which must ask user to enter PIN.
PinLockController* controller = [[PinLockController alloc] initWithStyle:PinLockTypeSet];
controller.delegate = m_Context;
// Here I lock the thread but not main thread (this is very important) I start
// ShowLockScreen function in new thread and lock it.
[conditionLock lock];
dispatch_sync(dispatch_get_main_queue(), ^{
// I call function which shows my UI in main thread as UI can be shown
// only in MAIN THREAD. (This is important too.)
[controller ShowLockController:conditionLock];
});
// Then I set lock to wait, how you can see I pass conditionLock as an
// argument to ShowLockController function in that function when user
// enter his PIN and press okay button I call [conditionLock signal];
// and my code code here after wait and continue executing.
[conditionLock wait];
NSLog(#"Come here then I call [conditionLock signal]!!!")
}
I'm invoking a NSOpenPanel from a thread created by boost C++.
the panel behaves erratically and doesn't respond well to mouse, that is clicking on objects does nothing sometime when clicking on top level combo box does improve response.
do i've to run a separate runloop I'm doing a runModalForDirectory which should take care of running its own loop.
I've also created a separate objc class which does performSelectorOnMainThread to show panel in main thread but still the behavior is same.
[ps performSelectorOnMainThread:#selector(showOpenPanel) withObject:nil
waitUntilDone:YES
modes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
I've also tried with waitUntilDone:NO and running a CFRunLoopRunInMode which isn't helping either.
- (bool) showOpenPanel
{
NSOpenPanel *op = [NSOpenPanel openPanel];
[op setAllowsMultipleSelection:YES];
[op setTitle:#"Choose File"];
[op setMessage:#"Choose file for Importing."];
[op setFloatingPanel:true];
bool result =[op runModalForDirectory:NSHomeDirectory() file:nil types:self.fileTypes];
if (result == NSOKButton) {
[self setSelectedFiles:[op filenames]];
[self setLastShowResult:true];
}
else {
[self setLastShowResult:false];
}
[self setPanelIsDone:true];
return self.lastShowResult;
}
NSOpenPanel is part of AppKit. AppKit functions and classes can only be safely used on the main thread.
Show us the code you used with performSelectorOnMainThread so we can help figure out why you might still be seeing problems. I suspect you're calling individual methods with it--don't; it won't work the way you expect. Call back to the main thread for the totality of your interaction with NSOpenPanel.