2

I'm trying make a simple async call using C++. My problem is that my code executing sync and use block functions. I want a async and non-blocking program.

First time, I wrote a little code in C++ to test my logic, so the program ends before thread so this not works. But on the Xcode on iOS project I can write C++ code without main function, on the Final Objective part is detailed it.

#include <iostream>
#include <string>
#include <chrono>
#include <future>

using namespace std;

void call_from_async()
{
    std::this_thread::sleep_for(std::chrono::seconds(5));
    cout << "Async call" << endl;
}

int main(void) {
    printf("1\n");
    std::future<void> fut = std::async(std::launch::async, call_from_async);
    // std::async(std::launch::async,call_from_async);
    printf("2\n");
    return 0;
}

Output:

1
2

Desired output:

1
2
Async Call

Final Objective

I've a Swift project and I must call C++ async functions. To do it, I want call a C++ function from Swift and pass a pointer function to get the callback when process has been finished. To start the project I just wrote a little code to call C++ function and leave the work make on background, when work is finished back to Swift throught callback function. I don't make a callback function yet, before I want test the async functions.

Swift code

// ViewController.swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        printFromCPP()
        print("1")
        call_async_function()
        print("2")
    }
}

// Ex_iOS_CPP_Swift-Bridging-Header.h

#ifdef __cplusplus
extern "C" {
#endif

#include "Foo.h"

#ifdef __cplusplus
}
#endif

// Foo.h

#ifndef Foo_h
#define Foo_h

void printFromCPP();
void call_async_function();

#endif /* Foo_h */

// Foo.cpp

#include <iostream>
#include <future>
#include <unistd.h>
#include "Ex_iOS_CPP_Swift-Bridging-Header.h"

using namespace std;

void called_from_async() {
    sleep(3);
    cout << "Async call" << endl;
}

void call_async_function() {
//    std::future<void> fut = std::async(std::launch::async, called_from_async);
    std::future<void> result( std::async(called_from_async));
}

void printFromCPP() {
    cout << "Hello World from CPP" << endl;
}

Output

Hello World from CPP
1
Async call
2

Desired output

Hello World from CPP
1
2
Async call
Augusto
  • 3,825
  • 9
  • 45
  • 93
  • 3
    You need to store the `std::future` returned by `async` otherwise it will block until the task finishes – François Andrieux Feb 20 '19 at 16:29
  • You can help me write the correct form this line `std::async(std::launch::async,call_from_async);` ? – Augusto Feb 20 '19 at 16:33
  • 1
    That should be fine. Your code compiles correctly [here](https://godbolt.org/z/2BJsMk). Any compiler that can provide `` should support `std::async` as they were introduced in the same c++ version. So I can't explain the error you have nor can I reproduce it. – François Andrieux Feb 20 '19 at 16:34
  • I'm using a macos, this apparentely not works. When I make this question my code was compiling correct – Augusto Feb 20 '19 at 16:36
  • @FrançoisAndrieux I tried use `std::future` but not solves, the code keeps sync and blocking. – Augusto Feb 20 '19 at 16:50
  • You need to call `fut.get()` after printing `2`. Otherwise the program will end before the thread has finished. – super Feb 20 '19 at 17:02
  • @super It turn my code sync and blocking... – Augusto Feb 20 '19 at 17:06
  • @Augusto Yes, `get` is blocking. But you still need to make sure all your threads are finished before ending the program. In a bigger program you could use `wait_for` to check for the result without blocking. – super Feb 20 '19 at 17:08
  • I'm doing interoperability between Swift code and C++ code, so the program never ends. – Augusto Feb 20 '19 at 17:09
  • Your example code clearly ends. If you have another example you should probably include that in the question. – super Feb 20 '19 at 17:10
  • @super you are alright, I edited the question. – Augusto Feb 20 '19 at 17:19

1 Answers1

3

This is how it can be done using Scapix Language Bridge:

C++

#include <thread>
#include <iostream>
#include <scapix/bridge/object.h>

class cpp_class : public scapix::bridge::object<cpp_class>
{
public:

    void async(std::function<void(std::string)> callback)
    {
        std::thread([=]{
            std::this_thread::sleep_for(std::chrono::seconds(3));
            std::cout << "cpp_class::async\n";
            callback("cpp_class::async -> success");
        }).detach();
    }
};

Swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let cpp = CppClass()

        cpp.async() {
            (result: String) in
            print("Swift: " + result)
        }
    }
}

This prints:

cpp_class::async
Swift: cpp_class::async -> success
Boris Rasin
  • 448
  • 4
  • 12