I walked away from WWDC 2016 with the understanding that we should be wary about using C-based struct API directly from Swift. In Concurrent Programming With GCD in Swift 3, talking about C-based locks, they were very specific:
... And in Swift, since you have the entire Darwin module at your disposition, you will actually see the struct based traditional C locks. However, Swift assumes that anything that is struct can be moved, and that doesn't work with a mutex or with a lock. So we really discourage you from using these kind of locks from Swift. ...
... And if you want something ... that looks like the locks that you have in C, then you have to call into Objective-C and introduce a base class in Objective-C that has your lock as an ivar.
And then you will expose lock and unlock methods, and a tryLock if you need it as well, that you will be able to call from Swift when you will subclass this class. ...
#implementation LockableObject {
os_unfair_lock _lock;
}
- (void)lock { os_unfair_lock_lock(&_lock); }
- (void)unlock { os_unfair_lock_unlock(&_lock); }
#end
However, watching WWDC 2019 Developing a Great Profiling Experience, I notice that the author is using os_unfair_lock directly from Swift, without this Objective-C wrapper, effectively:
private var workItemsLock = os_unfair_lock()
func subWorkItem(...) {
...
os_unfair_lock_lock(&self.workItemsLock)
...
os_unfair_lock_unlock(&self.workItemsLock)
...
}
Empirically, this sort of direct use of os_unfair_lock appears to work, but that doesn’t mean anything. Respecting the caveat in the 2016 WWDC video, I have refrained from using os_unfair_lock directly from Swift.
So, the question is, are they being (ever so slightly) sloppy in the use of this API in this 2019 sample? Or was the 2016 video incorrect in its claims? Or has the handling of C-based struct changed since Swift 3, now rendering this pattern safe?
The API example of using private var workItemsLock = os_unfair_lock() can fail at runtime.
The threading primitives from C need a stable memory location so to use them or another struct that has one of these primitives directly as a member of it you have to use UnsafePointer. The reason for this is that UnsafePointer APIs once they have allocated a chunk of memory that memory is stable and cannot be moved or trivially be copied by the compiler.
If you change the example like this it is now valid
private var workItemsLock: UnsafeMutablePointer<os_unfair_lock> = {
// Note, somewhere else this will need to be deallocated
var pointer = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
pointer.initialize(to: os_unfair_lock())
return pointer
}()
func subWorkItem(...) {
...
os_unfair_lock_lock(self.workItemsLock)
...
os_unfair_lock_unlock(self.workItemsLock)
...
}
Related
The problem
I am following a guide from the Microsoft Documentation and the examples there are given in C++. I could've just used the default samples in C++, but I wanted to further understand how the API works so I decided to rewrite the default C++ sample in C.
The problem I encountered is that I can easily call D2D1CreateFactory and create an ID2D1Factory, though when I was previously reading the documentation, it was stated that you have to always release the COM object after you've used it and don't need it anymore. The fact is that in C++ there's an inherited method Release from IUnknown. In C though there's no even a lpVtbl, which as far as I understand is usually needed for that purpose. The ID2D1Factory is just provided as a typedef and is an incomplete type.
And now I'm stuck, because I don't know how to release pointer. I've spent a couple of hours searching for ways to do that in C.
Is it even possible?
The header file: d2d1.h
The Code
Window Procedure simplified:
switch (uMessage)
{
case WM_CREATE:
{
HRESULT hResult = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &IID_ID2D1Factory, NULL, &pFactory);
if (FAILED(hResult))
{
return -1;
}
return 0;
}
...
}
Obviously pFactory is of an ID2D1Factory* type in global scope. It is zero-initialized by default (if that helps).
I have problem when try to call Swift instance method from c callback.
Error: "A C function pointer cannot be formed from a closure that captures context."
linphone_core_cbs_set_registration_state_changed(cbs) { (lc, cfg, state, message) in
switch state{
case LinphoneRegistrationOk:
print("LinphoneRegistrationOk")
self.call()
}
func call() {
let account = "test"
let domain = "sip.linphone.org"
let identity = "sip:" + account + "#" + domain
linphone_core_invite(lc, identity)
}
If you have the ability to pass an arbitrary void* as a context then using Unmanaged<SelfType>.passUnretained(self).toOpaque() and converting it back with Unmanaged<SelfType>.fromOpaque(context).takeUnretainedValue() is the best solution.
But based on your small snippet of (lc, cfg, state, message) none of them seem like a context pointer. So getting self back is still possible but likely more complex. Because you will need to create a global/static piece of data that can be accessed from inside your closure in a safe manner. Some ideas of how you can do this are below:
1) You can do this with just a simple global/static if you know that is safe.
2) You can use thread local storage and store a pointer to self and cast it back and forth in the same way as if you had the void* argument and used Unmanaged. This one of course requires that your C callback be raised on the same thread where you store the value.
3) If you have access to a unique identifier that both Swift and C can access that will continue to be valid and accessible in your callback you can create a map of type [UniqueIdentifierAccessibleBySwiftAndC: TypeOfSelf] and use that to get self back.
How can I define a thread safe global array with minimal modifications?
I want like every access to it to be accomplished by using mutex and synchronized block.
Something like this as 'T' will be some type (note that 'sync' keyword is not currently defined AFAIK):
sync Array!(T) syncvar;
And every access to it will be simmilar to this:
Mutex __syncvar_mutex;
//some func scope....
synchronized(__syncvar_mutex) { /* edits 'syncvar' safely */ }
My naive attempt was to do something like this:
import std.typecons : Proxy:
synchronized class Array(T)
{
static import std.array;
private std.array.Array!T data;
mixin Proxy!data;
}
Sadly, it doesn't work because of https://issues.dlang.org/show_bug.cgi?id=14509
Can't say I am very surprised though as automagical handling of multi-threading via hidden mutexes is very unidiomatic in modern D and the very concept of synchronized classes is mostly a relict from D1 times.
You can implement same solution manually, of course, by defining own SharedArray class with all necessary methods and adding locks inside the methods before calling internal private plain Array methods. But I presume you want something that work more out of the box.
Can't invent anything better right here and now (will think about it more) but it is worth noting that in general it is encouraged in D to create data structures designed for handling shared access explicitly instead of just protecting normal data structures with mutexes. And, of course, most encouraged approach is to not shared data at all using message passing instead.
I will update the answer if anything better comes to my mind.
It is fairly easy to make a wrapper around array that will make it thread-safe. However, it is extremely difficult to make a thread-safe array that is not a concurrency bottleneck.
The closest thing that comes to mind is Java's CopyOnWriteArrayList class, but even that is not ideal...
You can wrap the array inside a struct that locks the access to the array when a thread acquires a token and until it releases it.
The wrapper/locker:
acquire(): is called in loop by a thread. As it returns a pointer, the thread knows that it has the token when the method returns a non null value.
release(): is called by a thread after processing the data whose access has been acquired previously.
.
shared struct Locker(T)
{
private:
T t;
size_t token;
public:
shared(T) * acquire()
{
if (token) return null;
else
{
import core.atomic;
atomicOp!"+="(token, 1);
return &t;
}
}
void release()
{
import core.atomic;
atomicOp!"-="(token, 1);
}
}
and a quick test:
alias LockedIntArray = Locker!(size_t[]);
shared LockedIntArray intArr;
void arrayTask(size_t cnt)
{
import core.thread, std.random;
// ensure the desynchronization of this job.
Thread.sleep( dur!"msecs"(uniform(4, 20)));
shared(size_t[])* arr = null;
// wait for the token
while(arr == null) {arr = intArr.acquire;}
*arr ~= cnt;
import std.stdio;
writeln(*arr);
// release the token for the waiting threads
intArr.release;
}
void main(string[] args)
{
import std.parallelism;
foreach(immutable i; 0..16)
{
auto job = task(&arrayTask, i);
job.executeInNewThread();
}
}
With the downside that each block of operation over the array must be surrounded with an acquire/release pair.
You have the right idea. As an array, you need to be able to both edit and retrieve information. I suggest you take a look at the read-write mutex and atomic utilities provided by Phobos. A read operation is fairly simple:
synchronize on mutex.readLock
load (with atomicLoad)
copy the item out of the synchronize block
return the copied item
Writing should be almost exactly the same. Just syncronize on mutex.writeLock and do a cas or atomicOp operation.
Note that this will only work if you copy the elements in the array during a read. If you want to get a reference, you need to do additional synchronization on the element every time you access or modify it.
I'm trying to spawn a new thread to do some background processing, based on a String that I've broken down into an array of characters. Here's what my code looks like:
var testString : String = NSString(data:data!, encoding:NSUTF8StringEncoding)
var testStringArray : Array<Character> = []
for character in testString
{
if(!(self.isCharacterStrippable(character)))
{
testStringArray.append(character)
}
}
NSThread.detachNewThreadSelector("fillKeysFromArray:", toTarget: self, withObject: testStringArray)
I get a compiler error telling me that "Array does not conform to protocol AnyObject".
Short of writing an object wrapper for my array, or setting it as an instance variable (both of which seem like overkill), is there any way I can get this array passed through to the new thread?
Using Grand Central Dispatch is going to be much easier in the long run. You can run your function on a background thread with something like:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
[weak self] in // This is so that we don't create a reference cycle
self?.fillKeysFromArray(testStringArray);
return
}
You can read up on Grand Central Dispatch and all the nice things it provides when it comes to threading and concurrency in Apple's Concurrency Programming Guide.
The root cause is that detachNewThreadSelector can only accept a NSMutableArray for the withObject parameter. If you make testStringArray a variable of type NSMutableArray you can get rid of the compiler error message.
Having said that, you should seriously consider the advices from Bryan Chen and Mike S to switch to GCD.
I am struggling to implement an HID control with a Mac : I cannot send the expected function as depicted here below:
IOHIDManagerRegisterDeviceMatchingCallback( gIOHIDManagerRef, Handle_DeviceMatchingCallback, NULL );
with : gIOHIDManagerRef -> the valid HID manager dedicated to this routine
Handle_DeviceMatchingCallback --> the routine that will be called back when the HID
device is attached to the USB port
NUUL --> not used here, contain data from the USB
The issue is that Handle_DeviceMatchingCallback must be a pointer to the routine, but how can I send a pointer ?
On the other hand, all the examples , from the Apple source, are based on C, not on cocoa.
Well, does that means that I must rework my program in C ??? Or is it possible to have fraction of the program in C under the cocoa environment?
Sorry for so "stupid" question queries, but, although I have some background in the field of electronic an programming, I am very newbees with cocoa.
Your comments will be very appreciated !
Michael
Objective-C is mostly a super-set of C. In order to combine C and Objective-C code, you simply compile your C code as if it were Objective-C code. The easiest way to do this in Xcode is to ensure the file in question has a .m extension.
To route handling back to the Objective-C world, you need a pointer to an Obj-C object. Many callback-based APIs allow you to provide a generic pointer (void *) that they then pass back to you when they callback. This argument has several common names:
context or ctx
refcon (for "reference constant")
userData
userInfo
If the callback API does not allow this, you'll need some uglier way to dispatch the callback to your object, such as a global pointer or a lookup table.
The API you're using does let you provide a context pointer. When it calls back to your code, it provides you with the pointer you used when you registered for the callback. Here is an example of registering the callback from an object of type MyObjCClass (see the -registerMatching method below) and then using the context pointer to route the callback back to the object that registered the callback for handling (see the Handle_DeviceMatchingCallback function's use of the context pointer).
/*! #file C-ObjC-Callbacks.m
* Demonstrates routing a C callback to an Obj-C object
* using the callback's context pointer.
*/
#import <Cocoa/Cocoa.h>
#import <IOKit/hid/IOHIDManager.h>
// Global HID manager reference.
IOHIDManagerRef gIOHIDManager;
// HID callback
void Handle_DeviceMatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device);
#interface MyObjCClass : NSObject {
}
- (void)registerMatching;
- (void)handleMatchingDevice:(IOHIDDeviceRef)device
sender:(void *)sender
result:(IOReturn)result;
#end
#implementation MyObjCClass
- (void)registerMatching {
// Assume gIOHIDManager has already been created.
// Set up a device matching callback, providing a pointer to |self| as the context.
IOHIDManagerRegisterDeviceMatchingCallback(gIOHIDManager,
Handle_DeviceMatchingCallback,
(void *)self);
}
- (void)handleMatchingDevice:(IOHIDDeviceRef)device
sender:(void *)sender
result:(IOReturn)result {
// Do something...
}
#end
void
Handle_DeviceMatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device); {
MyObjCClass *const myObject = (MyObjCClass *const)context;
[myObject handleMatchingDevice:device sender:sender result:result];
}
Handle_DeviceMatchingCallback must be a pointer to the routine, but how
can I send a pointer ?
If you want to pass in a function functionName, you can pass it as
&functionName.
On the other hand, all the examples , from the Apple source, are based on
C, not on cocoa. Well, does that means that I must rework my program in C
??? Or is it possible to have fraction of the program in C under the cocoa
environment?
You can mix C and Objective-C at will. As long as you pass it a function,
and not a method attached to an object, it should work.