Skip to content

gil_scoped_acquire deadlock #1273

@KyleFromKitware

Description

@KyleFromKitware

Let's say we have the following minimal example:

#include <pybind11/pybind11.h>
#include <pybind11/embed.h>

#include <iostream>
#include <thread>

static void thread()
{
  pybind11::gil_scoped_acquire acquire;
  std::cout << "Calling Python code from new thread" << std::endl;
}

int main()
{
  pybind11::scoped_interpreter interp;

  {
    pybind11::gil_scoped_acquire acquire;
    std::cout << "Calling Python code from main thread" << std::endl;
  }

  std::thread(thread).join();

  return 0;
}

We would expect this to print:

Calling Python code from main thread
Calling Python code from new thread

But the cout from the new thread is never reached because of a GIL deadlock. The reason this is happening is because PyEval_InitThreads(), in addition to initializing threads, also acquires the GIL and never releases it. gil_scoped_acquire calls PyEval_InitThreads() the first time it runs, and it acquires the GIL a second time, so even when gil_scoped_acquire is destructed, the GIL is still held.

If we change the example to this:

#include <pybind11/pybind11.h>
#include <pybind11/embed.h>

#include <iostream>
#include <thread>

static void thread()
{
  pybind11::gil_scoped_acquire acquire;
  std::cout << "Calling Python code from new thread" << std::endl;
}

static void init_threads()
{
  if (!PyEval_ThreadsInitialized())
  {
    {
      pybind11::gil_scoped_acquire acquire;
    }
    PyEval_SaveThread();
  }
}

int main()
{
  pybind11::scoped_interpreter interp;

  init_threads();

  {
    pybind11::gil_scoped_acquire acquire;
    std::cout << "Calling Python code from main thread" << std::endl;
  }

  std::thread(thread).join();

  return 0;
}

then everything behaves as expected. Is this what I'm supposed to do, or is this a bug in pybind?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions