Calling into C functions from within a TaskGroup

I import a C library that defines a simple C function that prints some stuff to stdout: void libraryFunction(int, int). I call this function as shown below:

import Foundation
import MyCLibrary

@main
struct MySwiftPackage {
    static func main() async {
        await withTaskGroup(of: Void.self, body: { group in
            group.addTask {
                libraryFunction(0, 2500000)
            }
            group.addTask {
                libraryFunction(2500001, 5000000)
            }
            group.addTask {
                libraryFunction(5000001, 7500000)
            }
            group.addTask {
                libraryFunction(7500001, 10000000)
            }
        })
    }
}

The code compiles and runs. Results seem to always appear in sequential order from min..<max. Is it defined behavior of TaskGroup to always execute its Tasks in sequential order? Similar to a serial dispatch queue? Just found it very cool and useful to be able to call and use C code concurrently like so but wasn't sure if this was considered "safe" or "defined".

1 Like

As long as the underlying C function doesn't interact with shared mutable state, calling C code in concurrent Swift is perfectly fine.

However, execution order is not guaranteed - child tasks may be executed in parallel, with results arriving in the order they complete. The order you're seeing could be an artifact of the environment you're in (for instance, the iOS simulator is single-threaded, leading to much more deterministic timing), the library function executing extremely quickly (the tasks are added to the group serially, and if a task executes so quickly that it completes before the next one is added to the group, you'll get the serial behavior you're seeing), or any other combination of reasons.

4 Likes

If your workload does not benefit from Swift concurrency (I.e., you are not using await), then I find OperationQueues the better choice.