Multithreading

This tutorial demonstrates how to safely operate a Zivid camera from multiple threads. In the example that follows, we continuously poll the camera’s state in one thread while we simultaneously queue captures with the same camera from other threads.

Note

Zivid SDK supports operating the same camera from multiple threads at the same time from SDK 2.9.

First, we create different settings to distinguish between different captures. We use different exposure times to make it easy to notice the difference between the captures by observing the projected patterns.

std::cout << " Creating different settings to distinguish between different captures" << std::endl;
const auto settings0 =
    Zivid::Settings{ Zivid::Settings::Engine::phase,
                     Zivid::Settings::Acquisitions{ Zivid::Settings::Acquisition{
                         Zivid::Settings::Acquisition::Aperture{ 5.66 },
                         Zivid::Settings::Acquisition::Gain{ 1.0 },
                         Zivid::Settings::Acquisition::ExposureTime{ std::chrono::microseconds{ 10000 } } } } };
const auto settings1 = Zivid::Settings{ Zivid::Settings::Acquisitions{ settings0.acquisitions().at(0).copyWith(
    Zivid::Settings::Acquisition::ExposureTime{ std::chrono::microseconds{ 30000 } }) } };
const auto settings2 = Zivid::Settings{ Zivid::Settings::Acquisitions{ settings0.acquisitions().at(0).copyWith(
    Zivid::Settings::Acquisition::ExposureTime{ std::chrono::microseconds{ 90000 } }) } };

Then, we run a thread where we continuously check the state of the camera.

pollingThreads.emplace_back(std::async(std::launch::async, [&]() {
    while(!stop)
    {
        const auto state = camera.state();
        std::cout << "Camera: " << camera.info().serialNumber() << std::endl;
        std::cout << state << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    }
}));

Lastly, we spin three other threads to queue three captures, using different settings in each thread.

const auto frame0 = std::async(std::launch::async, [&]() { return camera.capture(settings0); });
const auto frame1 = std::async(std::launch::async, [&]() { return camera.capture(settings1); });
const auto frame2 = std::async(std::launch::async, [&]() { return camera.capture(settings2); });

As you can see, it is straightforward to operate the same camera from different threads. However, there are some limitations with certain APIs and situations that need to be avoided to guarantee a safe behavior of your program:

You must not operate the camera at the same time as calling any of the following APIs:

  • Zivid::Application::cameras()

  • Zivid::Camera::connect()

  • Zivid::Firmware::update()

The same holds for calling any combination of the above APIs simultaneously from multiple threads.

When using multiple Zivid cameras, it is important to list cameras and connect to cameras via the SDK sequentially.

std::cout << "Finding cameras" << std::endl;
auto cameras = zivid.cameras();
std::cout << "Number of cameras found: " << cameras.size() << std::endl;

// It is important to connect to cameras sequentially
for(auto &camera : cameras)
{
    std::cout << "Connecting to camera: " << camera.info().serialNumber().value() << std::endl;
    camera.connect();
}

We recommend connecting to all cameras in one thread and then spawning new threads that control cameras (it is thread safe to simultaneously “use” the same camera from multiple threads).