I just started doing some calculations into a background thread by creating a custom serial dispatch_queue. (Xcode 7.1 beta)
Now sometimes when I move the mouse really fast I get an error "pointer being freed was not allocated" triggered inside drawRect of my custom view.
The error occures inside a switch over an enum.
switch state {
case .Hide:
return
case .Show(let elements):
CGContextSetRGBFillColor(context, 1, 0.8, 0.2, 1)
CGContextSetRGBStrokeColor(context, 0.8, 0.5, 0.1, 1)
CGContextSetLineWidth(context, 1)
for e in elements {
drawDotAt(context, position: p.position, size: 5)
}
CGContextDrawPath(context, .FillStroke)
}
The enum is defined as:
public enum State {
case Hide
case Show([Element])
}
Element itself is a struct and looks somthing like this:
struct Element {
position: Vec2
label: String
radius: Double
}
As you can see there are only structs and enums involved.
For me the error looks like a race codition (the background task modifies the state) but until now I thought that structs and enums are threadsafe.
Now my question is: Is this the compiler's fault generating wrong code? Or is it my fault because I need my own locking mechanism preventing the drawRect code accessing the state value while the background task is modiying it?
I know that the code above is very superfacial and may be not enough information to debug the error but before I try building a working example I would like to have a more general answer on this problem: when getting a "pointer being freed was not allocated" error, is this something I have to take care of when doing multithreaded stuff? If yes: What is a general approach to solve this? some kind of double buffering? If not: Can I assume it is a compiler error?
Well, as a simple example, Swift Arrays (such as your [Element]) are implemented using referenced storage as a copy-on-write optimisation. If you start writing to it from multiple threads, then you can definitely see cases where your writes are not reflected in the final array. I imagine, but don't know, that you might also be able to corrupt the internal bookkeeping for the referenced storage and see issues like the one you report. inout parameters are implemented, semantically, as read-modify-write so you can probably see similar issues even with simple structs. But again, I'm not sure if this is causing the problem you report, I'm just addressing the question of thread safety.