ABAddressBookRef can only be accessed by one thread. I think a good model would be having a thread for ABAddressBookRef in the background, besides the main thread.
How can I ensure that there's only one thread while using NSOperationQueue? Simply setting max concurrency to 1 won't guarantee it to be run on the same thread.
Should I use other unique threads like web threads?
You can manually create a thread and redirect all address book access to it.
You create a thread with something like this (adapted from documentation):
NSThread* myThread = [[NSThread alloc] initWithTarget:[MyThread new]
selector:#selector(myThreadMainMethod)
object:nil];
[myThread start]; // Actually create the thread
Note that for the thread to be useful, you have to implement a run loop in thread's main method.
See example implementation of run loop in this answer.
You are then able to do stuff on this thread using the NSObject's method performSelector:onThread:withObject:waitUntilDone:.
Here's a wrapper library for ABAddressBookRef that implements this concept – RHAddressBook.
Related
I have tried to read as much as I can about PyQt4's QThread and the idea of the worker thread. My question is, instead of building a QThread class to run everything in it from the def run(self): by the blahblah.start() command is there a way to create that individual thread class that has,say, 4 functions and you only call function 2 and then close that thread right after?
Subclassing QThread is a practice that is in general discouraged although often used. [see comment below]
In my opinion, this is a good example of how to use a thread in pyqt. You would create a Worker and a Thread, where the Worker is some general class of type QObject and the Thread is a QThread which you do not subclass. You'd then move the Worker to the Threat and start it.
self.worker = WorkerObject()
self.worker_thread = QtCore.QThread()
self.worker.moveToThread(self.worker_thread)
self.worker_thread.start()
Inside the Worker you can basically do whatever you want, it can have arbitrary many methods and so on.
The one big thing to keep in mind is that the Worker needs to be separate from the main loop. So the methods should not return anything that is used in the main loop (better not return anything at all) and the Worker's results should be collected using signals and slots.
self.button_start.clicked.connect(self.worker.startWork)
self.button_do_something_else.clicked.connect(self.worker.function2)
self.worker.signalStatus.connect(self.updateStatus)
Also make sure not to use any PyQt/GUI objects inside the worker, as this would also build a bridge between Worker and main loop through PyQt itself.
I am using NSURLSession dataTaskWithURL:completionHandler. It looks like completionHandler is executed in a thread which is different than the thread(in my case, it's the main thread) which calls dataTaskWithURL. So my question is, since it is asynchronized, is it possible that the main thread exit, but the completionHandler thread is still running since the response has not come back, which is the case I am trying to avoid. If this could happen, how should I solve the problem? BTW, I am building this as a framework, not an application.Thanks.
In the first part of your question you seem un-sure that the completion handler is running on a different thread. To confirm this let's look at the NSURLSession Class Reference. If we look at the "Creating a Session" section we can see in the description for the following method the answer.
+ sessionWithConfiguration:delegate:delegateQueue:
Swift
init(configuration configuration: NSURLSessionConfiguration,
delegate delegate: NSURLSessionDelegate?,
delegateQueue queue: NSOperationQueue?)
Objective-C
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
delegate:(id<NSURLSessionDelegate>)delegate
delegateQueue:(NSOperationQueue *)queue
In the parameters table for the NSOperationQueue queue parameter is the following quote.
An operation queue for scheduling the delegate calls and completion handlers. The queue need not be a serial queue. If nil, the session creates a serial operation queue for performing all delegate method calls and completion handler calls.
So we can see the default behavior is to provide a queue whether from the developer or as the default class behavior. Again we can see this in the comments for the method + sessionWithConfiguration:
Discussion
Calling this method is equivalent to calling
sessionWithConfiguration:delegate:delegateQueue: with a nil delegate
and queue.
If you would like a more information you should read Apple's Concurrency Programming Guide. This is also useful in understanding Apple's approach to threading in general.
So the completion handler from - dataTaskWithURL:completionHandler: is running on a different queue, with queues normally providing their own thread(s). This leads the main component of your question. Can the main thread exit, while the completion handler is still running?
The concise answer is no, but why?
To answer this answer this we again turn to Apple's documentation, to a document that everyone should read early in their app developer career!
The App Programming Guide
The Main Run Loop
An app’s main run loop processes all user-related events. The
UIApplication object sets up the main run loop at launch time and uses
it to process events and handle updates to view-based interfaces. As
the name suggests, the main run loop executes on the app’s main
thread. This behavior ensures that user-related events are processed
serially in the order in which they were received.
All of the user interact happens on the main thread - no main thread, no main run loop, no app! So the possible condition you question mentions should never exist!
Apple seems more concerned with you doing background work on the main thread. Checkout the section "Move Work off the Main Thread"...
Be sure to limit the type of work you do on the main thread of your
app. The main thread is where your app handles touch events and other
user input. To ensure that your app is always responsive to the user,
you should never use the main thread to perform long-running or
potentially unbounded tasks, such as tasks that access the network.
Instead, you should always move those tasks onto background threads.
The preferred way to do so is to use Grand Central Dispatch (GCD) or
NSOperation objects to perform tasks asynchronously.
I know this answer is long winded, but I felt the need to offer insight and detail in answering your question - "the why" is just as important and it was good review :)
NSURLSessionTasks always run in background by default that's why we have completion handler which can be used when we get response from Web service.
If you don't get any response explore your request URL and whether HTTPHeaderFields are set properly.
Paste your code so that we can help it
I just asked the same question. Then figured out the answer. The thread of the completion handler is setup in the init of the NSURLSession.
From the documentation:
init(configuration configuration: NSURLSessionConfiguration,
delegate delegate: NSURLSessionDelegate?,
delegateQueue queue: NSOperationQueue?)`
queue - A queue for scheduling the delegate calls and completion handlers. If nil, the session creates a serial operation queue for performing all delegate method calls and completion handler calls.*
My code that sets up for completion on main thread:
var session = NSURLSession(configuration: configuration, delegate:nil, delegateQueue:NSOperationQueue.mainQueue())
(Shown in Swift, Objective-C the same) Maybe post more code if this does not solve.
According to http://doc.qt.io/qt-5/qpointer.html, QPointer is very useful. But I found it could be inefficient in the following context:
If I want to show label for three times or do something else, I have to use
if(label) label->show1();
if(label) label->show2();
if(label) label->show3();
instead of
if(label) { label->show1();label->show2();label->show3(); }
just because label might be destroyed in another thread after label->show1(); or label->show2();.
Is there a beautiful way other than three ifs to get the same functionality?
Another question is, when label is destroyed after if(label), is if(label) label->show1(); still wrong?
I don't have experience in multi-threaded programs. Any help is appreciated. ;)
I think the only safe way to do it is to make sure you only access your QWidgets from within the main/GUI thread (that is, the thread that is running Qt's event loop, inside QApplication::exec()).
If you have code that is running within a different thread, and that code wants the QLabels to be shown/hidden/whatever, then that code needs to create a QEvent object (or a subclass thereof) and call qApp->postEvent() to send that object to the main thread. Then when the Qt event loop picks up and handles that QEvent in the main thread, that is the point at which your code can safely do things to the QLabels.
Alternatively (and perhaps more simply), your thread's code could emit a cross-thread signal (as described here) and let Qt handle the event-posting internally. That might be better for your purpose.
Neither of your approaches is thread-safe. It's possible that your first thread will execute the if statement, then the other thread will delete your label, and then you will be inside of your if statement and crash.
Qt provides a number of thread synchronization constructs, you'll probably want to start with QMutex and learn more about thread-safety before you continue working on this program.
Using a mutex would make your function would look something like this:
mutex.lock();
label1->show();
label2->show();
label3->show();
mutex.unlock()
As long as your other thread is using locking that same mutex object then it will prevented from deleting your labels while you're showing them.
I have to perform a fetch via NSFetchedResultsController on a background thread.
My current solution is structured like that:
dispatch_queue_t fetchQueue = dispatch_queue_create("backgroundfetching", NULL);
dispatch_async(fetchQueue,^{
// 1. Create NSManagedObjectContext
// 2. Create NSFetchRequest
// 3. Create NSFetchedResultsController
// 4. PerformFetch
dispatch_async(dispatch_get_main_queue(),^{
[[self table] reloadData];
});
});
dispatch_release(fetchQueue);
My first tests ran well but is that the appropriate way?
Since the fetched results controller is intended to control the data that defines a tableview, it belongs on the foreground thread/operation that the UI runs on. It's rather pointless to put it on a background thread as you would lose all the advantages of using it in the first place.
I would also be concerned about the effects of sending the FRC delegate messages across asynchronous threads. I'm not sure how reliable that would be.
Having said all that, the sketch of your implementation looks fine as far as it goes.
I believe there is something fundamentally wrong with this approach, as you're sharing managed objects across threads (you're fetching objects on one thread and referencing them on your main thread). In practice it will work, but will sometimes lead to crashes. Because Apple makes it clear that the only ways to share managed objects across threads is using the objectWithID: method or the MOCDidSave notifications.
From the Core Data Programming Guide:
You fetch in one managed object context on a background thread, and
pass the object IDs of the fetched objects to another thread. In the
second thread (typically the application's main thread, so that you
can then display the results), you use the second context to fault in
objects with those object IDs (you use objectWithID: to instantiate
the object).
I want a function like GetCurrentThread which returns a TThread object of the current executing thread. I know there is a Win32 API call GetCurrentThread, but it returns the thread Id. If there is a possibility to get TThread object from that ID that's also fine.
From your own answer, it seems maybe you only want to "determine if running in the main thread or not", in which case you can just use
if Windows.GetCurrentThreadId() = System.MainThreadID then
// ...
Although this won't work from a DLL created with Delphi if it was loaded by a worker thread.
The latest version of Delphi, Delphi 2009, has a CurrentThread class property on the TThread class.
This will return the proper Delphi thread object if it's a native thread. If the thread is an "alien" thread, i.e. created using some other mechanism or on a callback from a third party thread, then it will create a wrapper thread around the thread handle.
I'm using my own TThread descendent that registers itself in a global list, protected with a lock.
That way, a method in this descendent can walk the list and get a TThread give an ID.
Answering my own question. I guess it is not possible to get TThread object from ID. It is possible by using a global variable. Then comparing its handle and current thread id, one can determine if running in the main thread or not.
Wouldn't the current executing thread be the one you're trying to run a function from?
You could store the pointer of the TThread instance in the current thread's context via the TlsSetValue API call and then retrieve it using TlsGetValue. However, note that this will only work if you're trying to retrieve/store the TThread instance of the current thread.