jupyter-xeus / xeus-cling

Jupyter kernel for the C++ programming language
BSD 3-Clause "New" or "Revised" License
3.08k stars 297 forks source link

IncrementalExecutor::executeFunction Error when working with futures and threads #428

Open jrmejiaa opened 2 years ago

jrmejiaa commented 2 years ago

Hi all,

I am working with xeus-cling to practice and make some notes about multi-threading in C++. As it was mentioned in the oficial documentation, I use the flag -pthread and lpthread to be able to work with threads in C++17 kernel.

Describe the Issue

When I am trying to use std::future and std::async the kernel collapse and it does not thrown the result as I was expected. The program works in my computer as expected, but inside of the environment it fails with the next error.

IncrementalExecutor::executeFunction: symbol '__emutls_v._ZSt11__once_call' unresolved while linking function '_GLOBAL__sub_I_cling_module_10'!
IncrementalExecutor::executeFunction: symbol '__emutls_v._ZSt15__once_callable' unresolved while linking function '_GLOBAL__sub_I_cling_module_10'!

To Reproduce

  1. Set the flags to work with threads in the kernel C++17 or C++14
  2. Set the next blocks of code
  3. Execute sequentially the bocks
  4. See error
#include <string>
#include <chrono>
#include <thread>

std::string fetchDataFromDB(std::string recvdData) {
    // Make sure that function takes 5 seconds to complete
    std::this_thread::sleep_for(std::chrono::seconds(2));
    //Do stuff like creating DB Connection and fetching Data
    return "DB_" + recvdData;
}
std::string fetchDataFromFile(std::string recvdData) {
    // Make sure that function takes 5 seconds to complete
    std::this_thread::sleep_for(std::chrono::seconds(2));
    //Do stuff like fetching Data File
    return "File_" + recvdData;
}
// Using async
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <future>

using namespace std::chrono;

// Get Start Time
system_clock::time_point start = system_clock::now();
std::future<std::string> resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
//Fetch Data from File
std::string fileData = fetchDataFromFile("Data");
//Fetch Data from DB
// Will block till data is available in future<std::string> object.
std::string dbData = resultFromDB.get();
// Get End Time
auto end = system_clock::now();
auto diff = duration_cast < std::chrono::seconds > (end - start).count();
std::cout << "Total Time Taken = " << diff << " Seconds" << std::endl;
//Combine The Data
std::string data = dbData + " :: " + fileData;
//Printing the combined Data
std::cout << "Data = " << data << std::endl;

Expected behavior

The output of the previous code should be:

Total Time Taken = 2 Seconds
Data = DB_Data :: File_Data

I use the same code without std::async and std::future, which would make the code sequentiell and it works as expected, so the problem is indeed when I am using those features of C++11