首页 \ 问答 \ 线程之间的通信(communication between threads)

线程之间的通信(communication between threads)

我正在制作一个小游戏,其中我将有两个线程(以及迈向多线程的第一步......),一个用于逻辑,一个用于绘图。

所以我的问题是:我怎样才能使这两者相互沟通呢?

要求:

  • 从另一个线程访问变量和对象

  • 同步它们,使它们在同一时间内完成相同数量的“循环”。 (逻辑计算,然后另一个绘制结果,循环再次开始...)

那么这在java中是如何实现的呢?

提前致谢!


I'm making a little java game in which I would have two threads (well as the FIRST step towards multithreading...), one for the logic and one for the drawing.

So my question is: How can I make those two communicating which each other?

Requirements:

  • accessing variables and object from a another thread

  • syncing them so they each complete a same number of "loops" in the same time. (the logic calculates and then the another one draws the results and the loop begins again...)

So how is this achievable in java?

Thanks in advance!


原文:https://stackoverflow.com/questions/10970323
更新时间:2023-07-24 17:07

最满意答案

Boost.Python只接受指向函数的指针和指向成员函数的指针。 所以我们需要做的是将我们的callable转换为函数指针。 这里的关键思想是

  1. 没有捕获的lambda可以转换为函数指针(通过巫术
  2. 函数指针的解释方式与Python中的成员函数相同:第一个参数是self

所以在你的情况下,我们需要做的是生成这个lambda:

+[](gui_button_t* self) {
    self->on_pressed();
}

你已经可以在Boost.Python中使用它了,因为这是一个非常正常的函数指针。 但是,我们需要一个适用于任何可调用成员的解决方案。 当你可以支持任何东西时,为什么支持boost::function

我们将从@ Columbo的closure_traits ,但另外添加一种方法来拉出参数列表;

template <typename...> struct typelist { };

template <typename C, typename R, typename... Args>                        \
struct closure_traits<R (C::*) (Args... REM_CTOR var) cv>                  \
{                                                                          \
    using arity = std::integral_constant<std::size_t, sizeof...(Args) >;   \
    using is_variadic = std::integral_constant<bool, is_var>;              \
    using is_const    = std::is_const<int cv>;                             \
                                                                           \
    using result_type = R;                                                 \
                                                                           \
    template <std::size_t i>                                               \
    using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; \
                                                                           \
    using args = typelist<Args...>;                                        \
};

然后我们将为任何可调用成员编写一个包装器。 由于我们的lambda可以不捕获,我们必须将callable作为模板参数:

template <typename CLS, typename F, F CLS::*callable>
class wrap { ... };

我将使用C ++ 14的auto返回类型演绎来节省一些打字。 我们创建一个顶级的make_pointer()静态成员函数,该函数只转发给另外获取参数的辅助成员函数。 完整wrap看起来像:

template <typename CLS, typename F, F CLS::*callable>
class wrap {
public:
    static auto make_pointer() {
        return make_pointer_impl(typename closure_traits<F>::args{});
    }

private:
    template <typename... Args>
    static auto make_pointer_impl(typelist<Args...> ) {
        // here is our lambda that takes the CLS as the first argument
        // and then the rest of the callable's arguments,
        // and just calls it
        return +[](CLS* self, Args... args) {
            return (self->*callable)(args...);
        };
    }
};

我们可以用它来包装你的按钮:

void (*f)(gui_button_t*) = wrap<gui_button_t, 
                                decltype(gui_button_t::on_pressed),
                                &gui_button_t::on_pressed
                                >::make_pointer();

这有点冗长和重复,所以让我们做一个宏(叹息):

#define WRAP_MEM(CLS, MEM) wrap<CLS, decltype(CLS::MEM), &CLS::MEM>::make_pointer()

所以我们得到:

void (*f)(gui_button_t*) = WRAP_MEM(gui_button_t, on_pressed);

f(some_button); // calls some_button->on_pressed()

由于这给了我们一个指向函数的指针,我们可以直接使用普通的Boost.Python API:

class_<gui_button_t>("GuiButton", init<>())
    .def("on_pressed", WRAP_MEM(gui_button_t, on_pressed));

演示演示成员std::function函数指针和带有operator()的成员struct


以上使您能够公开可调用的。 如果你想另外能够做任务,即:

button = GuiButton()
button.on_pressed = callback_function
button.on_pressed()

我们需要做点别的事情。 您无法在Python中以有意义的方式公开operator= ,因此为了支持上述功能,您必须覆盖__setattr__ 。 现在,如果你愿意:

button.set_on_pressed(callback_function)

我们可以扩展上面的wrap解决方案来添加一个setter,其实现方式将如上所述:

static auto set_callable() {
    return make_setter_impl(
        typelist<typename closure_traits<F>::result_type>{},
        typename closure_traits<F>::args{});
}

template <typename R, typename... Args>
static auto make_setter_impl(typelist<R>, typelist<Args...> ) {
    return +[](CLS* self, py::object cb) {
        (self->*callable) = [cb](Args... args) {
            return py::extract<R>(
                cb(args...))();
        };
    };
}

// need a separate overload just for void
template <typename... Args>
static auto make_setter_impl(typelist<void>, typelist<Args...> ) {
    return +[](CLS* self, py::object cb) {
        (self->*callable) = [cb](Args... args) {
            cb(args...);
        };
    };
}

#define SET_MEM(CLS, MEM) wrap<CLS, decltype(CLS::MEM), &CLS::MEM>::set_callable()

然后您可以通过以下方式公开:

.def("set_on_pressed", SET_MEM(button, on_pressed))

但是,如果您坚持支持直接分配,那么您还需要另外暴露以下内容:

static void setattr(py::object obj, std::string attr, py::object val)
{
     if (attr == "on_pressed") {
         button& b = py::extract<button&>(obj);
         SET_MEM(button, on_pressed)(&b, val);
     }
     else {
         py::str attr_str(attr);
         if (PyObject_GenericSetAttr(obj.ptr(), attr_str.ptr(), val.ptr()) {
             py::throw_error_already_set();
         }
     }
}


.def("__setattr__", &button::setattr);

这样可行,但您必须为要设置的每个仿函数添加更多个案。 如果每个类只有一个类似仿函数的对象,可能不是什么大问题,甚至可以编写更高阶的函数来为给定的属性名称生成特定的类似setattr的函数。 但是如果你有倍数,它将比简单的set_on_pressed解决方案稳定地变得更糟。


如果C ++ 14不可用,我们必须只显式指定make_pointer的返回类型。 我们需要一些方便的类型特征。 concat

template <typename T1, typename T2>
struct concat;

template <typename T1, typename T2>
using concat_t = typename concat<T1, T2>::type;

template <typename... A1, typename... A2>
struct concat<typelist<A1...>, typelist<A2...>> {
    using type = typelist<A1..., A2...>;
};

然后将返回类型和typelist转换为函数指针:

template <typename R, typename T>
struct make_fn_ptr;

template <typename R, typename... Args>
struct make_fn_ptr<R, typelist<Args...>> {
    using type = R(*)(Args...);
};

template <typename R, typename T>
using make_fn_ptr_t = typename make_fn_ptr<R, T>::type;

然后在wrap ,我们可以将结果类型定义为:

using R = make_fn_ptr_t<
                typename closure_traits<F>::result_type,
                concat_t<
                    typelist<CLS*>,
                    typename closure_traits<F>::args
                    >
                >;

并使用它而不是autoC ++ 11演示


Boost.Python only accepts pointers to functions and pointers to member functions. So what we need to do is convert our callable into a function pointer. The key ideas here are that

  1. a lambda that has no capture can be converted to a function pointer (via sorcery)
  2. function pointers are interpreted the same way as member functions in Python: the first argument is self

So in your case, what we need to do is generate this lambda:

+[](gui_button_t* self) {
    self->on_pressed();
}

You can already use that as-is with Boost.Python, since that is a perfectly normal pointer to function. However, we want a solution that will work for any callable member. Why just support boost::function when you can support anything?

We'll start with @Columbo's closure_traits, but additionally adding a way to pull out the argument list;

template <typename...> struct typelist { };

template <typename C, typename R, typename... Args>                        \
struct closure_traits<R (C::*) (Args... REM_CTOR var) cv>                  \
{                                                                          \
    using arity = std::integral_constant<std::size_t, sizeof...(Args) >;   \
    using is_variadic = std::integral_constant<bool, is_var>;              \
    using is_const    = std::is_const<int cv>;                             \
                                                                           \
    using result_type = R;                                                 \
                                                                           \
    template <std::size_t i>                                               \
    using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; \
                                                                           \
    using args = typelist<Args...>;                                        \
};

Then we'll write a wrapper for any callable member. Since our lambda can take NO capture, we have to take the callable as a template parameter:

template <typename CLS, typename F, F CLS::*callable>
class wrap { ... };

I will use C++14's auto return type deduction to save some typing. We make a top-level make_pointer() static member function that just forwards to a helper member function that additionally takes the arguments. The full wrap looks like:

template <typename CLS, typename F, F CLS::*callable>
class wrap {
public:
    static auto make_pointer() {
        return make_pointer_impl(typename closure_traits<F>::args{});
    }

private:
    template <typename... Args>
    static auto make_pointer_impl(typelist<Args...> ) {
        // here is our lambda that takes the CLS as the first argument
        // and then the rest of the callable's arguments,
        // and just calls it
        return +[](CLS* self, Args... args) {
            return (self->*callable)(args...);
        };
    }
};

Which we can use to wrap your button:

void (*f)(gui_button_t*) = wrap<gui_button_t, 
                                decltype(gui_button_t::on_pressed),
                                &gui_button_t::on_pressed
                                >::make_pointer();

That's a little verbose and repetitive, so let's just make a macro (sigh):

#define WRAP_MEM(CLS, MEM) wrap<CLS, decltype(CLS::MEM), &CLS::MEM>::make_pointer()

So we get:

void (*f)(gui_button_t*) = WRAP_MEM(gui_button_t, on_pressed);

f(some_button); // calls some_button->on_pressed()

Since this gives us a pointer to function, we can use this directly with the normal Boost.Python API:

class_<gui_button_t>("GuiButton", init<>())
    .def("on_pressed", WRAP_MEM(gui_button_t, on_pressed));

Demo demonstrating function pointers to a member std::function and a member struct with an operator().


The above gets you the ability to expose a callable. If you want to additionally be able to do assignment, i.e.:

button = GuiButton()
button.on_pressed = callback_function
button.on_pressed()

We'll need to do something else. You can't expose operator= in a meaningful way in Python, so to support the above functionality, you'd have to override __setattr__ instead. Now, if you were open to:

button.set_on_pressed(callback_function)

we could extend the above wrap solution to add a setter, whose implementation would be, in the vein of the above:

static auto set_callable() {
    return make_setter_impl(
        typelist<typename closure_traits<F>::result_type>{},
        typename closure_traits<F>::args{});
}

template <typename R, typename... Args>
static auto make_setter_impl(typelist<R>, typelist<Args...> ) {
    return +[](CLS* self, py::object cb) {
        (self->*callable) = [cb](Args... args) {
            return py::extract<R>(
                cb(args...))();
        };
    };
}

// need a separate overload just for void
template <typename... Args>
static auto make_setter_impl(typelist<void>, typelist<Args...> ) {
    return +[](CLS* self, py::object cb) {
        (self->*callable) = [cb](Args... args) {
            cb(args...);
        };
    };
}

#define SET_MEM(CLS, MEM) wrap<CLS, decltype(CLS::MEM), &CLS::MEM>::set_callable()

Which you could then expose via:

.def("set_on_pressed", SET_MEM(button, on_pressed))

However, if you insist on supporting direct-assignment, then you would need to additionally expose something like:

static void setattr(py::object obj, std::string attr, py::object val)
{
     if (attr == "on_pressed") {
         button& b = py::extract<button&>(obj);
         SET_MEM(button, on_pressed)(&b, val);
     }
     else {
         py::str attr_str(attr);
         if (PyObject_GenericSetAttr(obj.ptr(), attr_str.ptr(), val.ptr()) {
             py::throw_error_already_set();
         }
     }
}


.def("__setattr__", &button::setattr);

That would work, but you'd have to add more cases for each functor you want to set. If you only have one functor-like object per class, probably not a big deal, and can even write a higher order function to product a specific setattr-like function for a given attribute name. But if you have multiples, it's going to steadily get worse than the simple set_on_pressed solution.


If C++14 is not available, we'll have to just explicitly specify the return type of make_pointer. We'll need a few handy type traits. concat:

template <typename T1, typename T2>
struct concat;

template <typename T1, typename T2>
using concat_t = typename concat<T1, T2>::type;

template <typename... A1, typename... A2>
struct concat<typelist<A1...>, typelist<A2...>> {
    using type = typelist<A1..., A2...>;
};

And then something to turn a return type and a typelist into a function pointer:

template <typename R, typename T>
struct make_fn_ptr;

template <typename R, typename... Args>
struct make_fn_ptr<R, typelist<Args...>> {
    using type = R(*)(Args...);
};

template <typename R, typename T>
using make_fn_ptr_t = typename make_fn_ptr<R, T>::type;

And then within wrap, we can just define a result type as:

using R = make_fn_ptr_t<
                typename closure_traits<F>::result_type,
                concat_t<
                    typelist<CLS*>,
                    typename closure_traits<F>::args
                    >
                >;

and use that instead of auto. C++11 Demo.

相关问答

更多
  • 当调用通过Boost.Python公开的函数时,Boost.Python将查询其注册表,以根据所需的C ++类型为每个调用者的参数找到合适的from-Python转换器。 如果找到一个知道如何从Python对象转换为C ++对象的转换器,那么它将使用转换器来构造C ++对象。 如果找不到合适的转换器,则Boost.Python将引发ArgumentError异常。 from-Python转换器已注册: 自动用于Boost.Python支持的类型,例如int和std::string 对于boost::pyth ...
  • 如何通过Boost.Pyhton从Python调用C ++函数时释放GIL: http://wiki.python.org/moin/boost.python/HowTo#Multithreading_Support_for_my_function The answer is no, the GIL will never truly multi-thread unless the DLL manually releases the lock. Python allows exactly one thread ...
  • 那么,我很愚蠢。 要链接一个,必须将带有符号的库之前的对象。 如此转身 g++ -shared -Wl,-soname,"libhello.so" -L/usr/local/lib -lboost_python -fpic -o libhello.so hello.o 成 g++ -shared -Wl,-soname,"libhello.so" -L/usr/local/lib hello.o -lboost_python -fpic -o libhello.so 在我用cxxflags = -fPI ...
  • 将functor作为方法公开并不正式支持 。 支持的方法是公开一个委托给成员函数的非成员函数。 但是,这可能会导致大量的样板代码。 尽我所知,Boost.Python的实现并没有明确地排除函数,因为它允许将python::object实例作为方法公开。 但是,Boost.Python确实对作为方法公开的对象类型提出了一些要求: 仿函数是CopyConstructible。 函数是可调用的。 即实例o可以被称为o(a1, a2, a3) 。 呼叫签名在运行时必须作为元数据提供。 Boost.Python调用b ...
  • 我认为你可以使用boost::weak_ptr 。 using boost::shared_ptr; using boost::weak_ptr; func (weak_ptr wp) { shared_ptr sp = wp.lock (); if (sp) // sp stays alive until it goes out of scope or is reset } 基本上,这是boost::weak_ptr文档中提供的示例。 这是参考 。 ...
  • 经过一些研究,我找到了答案。 您也可以为.def提供静态函数。 只需将其to_iso_extended_string ,它就会将对象作为第一个参数。 BOOST_PYTHON_MODULE(mymodule) { class_("Date") .add_property("year", &boost::gregorian::date::year) .add_property("month", &boost::gregor ...
  • 这段代码有效。 我无法返回QSize&c。 虽然通过内部参考,但按价值返回工作正常。 This code worked. I wasn't able to return QSize &c. by internal reference though, but returning by value worked fine.
  • 当需要从C ++调用Python,并且C ++拥有main函数时,必须将 Python中断器嵌入到C ++程序中。 Boost.Python API不是Python / C API的完整包装器,因此可能会发现需要直接调用部分Python / C API。 尽管如此,Boost.Python的API可以使互操作性更容易。 考虑阅读官方的Boost.Python 嵌入教程以获取更多信息。 这是嵌入Python的C ++程序的基本框架: int main() { // Initialize Python. ...
  • Boost.Python只接受指向函数的指针和指向成员函数的指针。 所以我们需要做的是将我们的callable转换为函数指针。 这里的关键思想是 没有捕获的lambda可以转换为函数指针(通过巫术 ) 函数指针的解释方式与Python中的成员函数相同:第一个参数是self 所以在你的情况下,我们需要做的是生成这个lambda: +[](gui_button_t* self) { self->on_pressed(); } 你已经可以在Boost.Python中使用它了,因为这是一个非常正常的函数指 ...
  • 在您的C或C ++代码中,为SIGINT安装一个信号处理程序,它设置一个全局标志,让你的长时间运行的函数定期检查该标志,并在设置标志时提前返回。 或者,您可以使用Python C API引发Python异常,而不是提前返回:请参阅此处的 PyErr_SetInterrupt。 In your C or C++ code, install a signal handler for SIGINT that sets a global flag and have your long-running functio ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。