I'm attempting to create a multithreaded transition animation system, but am confused by seemingly corrupted state in an NSCondition object I'm using for synchronization. I've added some lines from my debugger below to illustrate what's happening:
po [NSThread currentThread]
<NSThread: 0x146f77a0>{name = Transition Animation, num = 4}
po _condition
<NSCondition: 0x1464dff0>{locked = YES, thread = 0xb083b000, name = nil}
p *(NSCondition*)_condition
(NSCondition) $5 = {
NSObject = {
isa = NSCondition
}
_priv = 0x00000000
}
What's confusing me is the address and name given by the condvar's description since they don't match up with the name and address of the NSThread that's calling -lock on the condition. Additionally, inspecting the actual contents of the NSCondition itself isn't helpful since its _priv pointer is nil. Does anyone have any experience with this or know how to fix it?
P.S. Before people suggest that I just use GCD for concurrency: I'm using CADisplayLinks for my animation, so I need to use NSThreads since CADisplayLinks require an NSRunLoop to trigger updates.
Related
I have a shared-memory between multiple threads. I want to prevent these threads access this piece of memory at a same time. (like producer-consumer problem)
Problem:
A thread add elements to a queue and another thread reads these elements and delete them. They shouldn't access the queue simultaneously.
One solution to this problem is to use Mutex.
As I found, there is no Mutex in Swift. Is there any alternatives in Swift?
There are many solutions for this but I use serial queues for this kind of action:
let serialQueue = DispatchQueue(label: "queuename")
serialQueue.sync {
//call some code here, I pass here a closure from a method
}
Edit/Update: Also for semaphores:
let higherPriority = DispatchQueue.global(qos: .userInitiated)
let lowerPriority = DispatchQueue.global(qos: .utility)
let semaphore = DispatchSemaphore(value: 1)
func letUsPrint(queue: DispatchQueue, symbol: String) {
queue.async {
debugPrint("\(symbol) -- waiting")
semaphore.wait() // requesting the resource
for i in 0...10 {
print(symbol, i)
}
debugPrint("\(symbol) -- signal")
semaphore.signal() // releasing the resource
}
}
letUsPrint(queue: lowerPriority, symbol: "Low Priority Queue Work")
letUsPrint(queue: higherPriority, symbol: "High Priority Queue Work")
RunLoop.main.run()
Thanks to beshio's comment, you can use semaphore like this:
let semaphore = DispatchSemaphore(value: 1)
use wait before using the resource:
semaphore.wait()
// use the resource
and after using release it:
semaphore.signal()
Do this in each thread.
As people commented (incl. me), there are several ways to achieve this kind of lock. But I think dispatch semaphore is better than others because it seems to have the least overhead. As found in Apples doc, "Replacing Semaphore Code", it doesn't go down to kernel space unless the semaphore is already locked (= zero), which is the only case when the code goes down into the kernel to switch the thread. I think that semaphore is not zero most of the time (which is of course app specific matter, though). Thus, we can avoid lots of overhead.
One more comment on dispatch semaphore, which is the opposite scenario to above. If your threads have different execution priorities, and the higher priority threads have to lock the semaphore for a long time, dispatch semaphore may not be the solution. This is because there's no "queue" among waiting threads. What happens at this case is that higher priority
threads get and lock the semaphore most of the time, and lower priority threads can lock the semaphore only occasionally, thus, mostly just waiting. If this behavior is not good for your application, you have to consider dispatch queue instead.
You can use NSLock or NSRecursiveLock. If you need to call one locking function from another locking function use recursive version.
class X {
let lock = NSLock()
func doSome() {
lock.lock()
defer { lock.unlock() }
//do something here
}
}
I have a loop which I run and in each iteration I have a block that I want run on an NSOperationQueue. The underlying queue is serial. This loop could add hundreds of potentially long running block tasks. When I set m_opQueue.suspended = YES the blocks will still keep executing.
I'm well aware that a single block cannot stop right in the middle, but I expected that pausing the NSOperationQueue would simply not execute the next operation until suspended was false.
Can anyone explain whether I'm wrong or how I achieve what I want?
dispatch_queue_t index_queue = dispatch_queue_create("someQueue", DISPATCH_QUEUE_SERIAL);
m_OpQueue = [[NSOperationQueue alloc] init];
m_OpQueue.underlyingQueue = index_queue;
for ( NSUInteger i = 0; i < total; i++ ) {
void (^block)(void) = ^void() {
// Do stuff.
NSLog(#"processing complete.");
};
// Effectively adds a NSBlockOperation.
[m_OpQueue addOperationWithBlock:block];
}
This curious behavior you describe (where previously enqueued operations will continue to start even after the queue has been suspended), is caused by how you created the serial queue.
Generally, you create a serial operation queue by setting maxConcurrentOperationCount:
m_OpQueue.maxConcurrentOperationCount = 1;
If you do that (no need to set underlyingQueue), you see the expected behavior.
Hi I am building an app using Swift. I need to process notifications in a specific order. Therefore I am trying to use addOperations waitUntilFinished.
Here is what I did:
let oldify = NSOperation()
oldify.completionBlock = {
println("oldify")
}
let appendify = NSOperation()
appendify.completionBlock = {
println("appendify")
}
let nettoyify = NSOperation()
nettoyify.completionBlock = {
println("nettoyify")
}
NSOperationQueue.mainQueue().maxConcurrentOperationCount = 1
NSOperationQueue.mainQueue().addOperations([oldify, appendify, nettoyify], waitUntilFinished: true)
With this code none of the operations is being executed. When I try this instead:
NSOperationQueue.mainQueue().maxConcurrentOperationCount = 1
NSOperationQueue.mainQueue().addOperation(oldify)
NSOperationQueue.mainQueue().addOperation(appendify)
NSOperationQueue.mainQueue().addOperation(nettoyify)
The operations get executed but not in the right order.
Does anyone know what I'm doing wrong? I am getting confident in swift but completely new to NSOperations
A couple of issues:
You are examining behavior of the completion block handlers. As the completionBlock documentation says:
The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context.
The queue will manage the operations themselves, but not their completion blocks (short of making sure that the the operation finishes before its completionBlock is started). So, bottom line, do not make any assumptions about (a) when completion blocks are run, (b) the relation of one operation's completionBlock to other operations or their completionBlock blocks, etc., nor (c) which thread they are performed on.
Operations are generally executed in the order in which they were added to the queue. If you add an array of operations, though, the documentation makes no formal assurances that they are enqueued in the order they appear in that array. You might, therefore, want to add the operations one at a time.
Having said that, the documentation goes on to warn us:
An operation queue executes its queued operation objects based on their priority and readiness. If all of the queued operation objects have the same priority and are ready to execute when they are put in the queue—that is, their isReady method returns YES—they are executed in the order in which they were submitted to the queue. However, you should never rely on queue semantics to ensure a specific execution order of operation objects. Changes in the readiness of an operation can change the resulting execution order. If you need operations to execute in a specific order, use operation-level dependencies as defined by the NSOperation class.
To establish explicit dependencies, you might do something like:
let oldify = NSBlockOperation() {
NSLog("oldify")
}
oldify.completionBlock = {
NSLog("oldify completion")
}
let appendify = NSBlockOperation() {
NSLog("appendify")
}
appendify.completionBlock = {
NSLog("appendify completion")
}
appendify.addDependency(oldify)
let nettoyify = NSBlockOperation() {
NSLog("nettoyify")
}
nettoyify.completionBlock = {
NSLog("nettoyify completion")
}
nettoyify.addDependency(appendify)
let queue = NSOperationQueue()
queue.addOperations([oldify, appendify, nettoyify], waitUntilFinished: false)
BTW, as you'll see above, you should not add operations to the main queue in conjunction with the waitUntilFinished. Feel free to add them to a different queue, but don't dispatch from a serial queue, back to itself, with the waitUntilFinished option.
I need to write simple watchdog which could detect deadlocks in iOS.
I already implemented simple one using GCD dispatch source working as a timer which increments a counter (dispatching on main thread).
This works quite nice for detecting if main thread did stuck but I would like to improve it by being able to detect deadlock on any thread.
My idea is for periodically loop throughout all threads and compare thread backtraces between checks, but I am not sure it it is good approach:
PSEUDO-CODE:
const task_t this_task = mach_task_self();
const thread_t this_thread = mach_thread_self();
kern_return_t kr;
thread_act_array_t threads;
mach_msg_type_number_t thread_count;
kr = task_threads(this_task, &threads, &thread_count);
for (mach_msg_type_number_t i = 0; i < thread_count; i++) {
// 0. get thread:
thread_t thread = threads[i];
// 1. do not analyze this thread (it is an watchdog thread):
if (this_thread == thread)continue;
// 2. suspend thread for a moment:
if((kr = thread_suspend(thread)) != KERN_SUCCESS)continue;
// 3. get backtrace:
int backtraceLength = ksbt_backtraceThread(thread, (uintptr_t*)backtrace, sizeof(backtrace));
// 4. todo - compare.... (HOW TO???)
Anyone can help if comparing backtraces is good approach to detect if thread did stuck or is there better POSIX method?
I have this below in my iOS app.
I am learning GCD. so, trying out the simple things.
Here, The output of this is confusing me.
Why always the 2. set of statements are coming first and then 1.?
Even though I am dispatching the two tasks to GCD, first I am dispatching 1. set first. It is not really a huge task so that 1. set and 2.set will overlap in time. Its just a simple task to print what threads it is running on.
I have run it several times expecting that it would give different results as how it happens in threading environment.
Please describe.
2. Crnt Thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
2. Main thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
1. Crnt Thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
1. Main thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
3. Crnt Thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
3. Main thread = <NSThread: 0x10920fee0>{name = (null), num = 1}
Code here:
void displayAlertView(void *paramContext)
{
NSLog(#"3. Crnt Thread = %#",[NSThread currentThread]);
NSLog(#"3. Main thread = %#", [NSThread mainThread]);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
dispatch_queue_t myQueue = dispatch_get_main_queue();
AlertViewData *contextData = (AlertViewData *)malloc(sizeof(AlertViewData));
dispatch_async(myQueue,^(void){
NSLog(#"1. Crnt Thread = %#",[NSThread currentThread]);
NSLog(#"1. Main thread = %#", [NSThread mainThread]);
});
if(contextData != NULL)
{
NSLog(#"2. Crnt Thread = %#",[NSThread currentThread]);
NSLog(#"2. Main thread = %#", [NSThread mainThread]);
dispatch_async_f(myQueue, contextData, displayAlertView);
}
return YES;
}
The "2" statements come first because that code is getting executed before the asynchronous block has had a chance to be setup and run. That's the whole point of dispatch_async. Such code gets run on another thread while the current thread continues on its merry way.
If you updated both blocks of code to use a loop that logs 100 logs statements, then you would probably see some mixing of "1" and "2" statements.
But with just the two logs, they happen so fast, the "2" logs complete before the block with the "1" logs has had a chance to kick in. Look at the timestamps in the log to see.
UPDATE
The above was written under the assumption that myQueue was a background queue. As Martin pointed out, it's the main queue. Since it is the main queue, the answer is quite a bit different.
Since you are doing asynchronous calls on the main queue, everything is done on the same main thread. Each call to dispatch_async is like adding it to the end of the line.
The currently running code is at the head of the line. When you call dispatch_async for the block with the "1" logs, that block is added to the end of the line and will be run when the current code is done. Then you call the dispatch_async_f for the "3" logs. Those get added to the end the line (after the "1" logs).
So once the current runloop completes (and the didFinishLaunchingWithOptions` method returns), then the next bit in line is run. This is your "1" logs. When that is done, the next block in the queue is run (your "3" logs).