线程间函数调用
1 四种api调用
在libcamera中,类和线程通过Object绑定,它们的关系为:
Object通过Thread实现invokeMethod(),类继承Object,外部就可以通过类指针调用invokeMethod()了。
b->invokeMethod(B::func, Type, param...),调用类型Type有下面4中。
1.1 direct
直接在当前线程调用,就像调用普通函数一样。
1.2 queued
总是去目标线程排队调用;非阻塞,不等待调用结果。
1.3 auto
如果调用线程和目标线程一致,类似普通函数直接调用;
如果调用线程和目标线程不一致,排队调用,非阻塞;
1.4 blocking
如果调用线程和目标线程一致,类似普通函数直接调用;
如果调用线程和目标线程不一致,排队调用,等待调用结果;
2 情况分析
2.1 线程安全
如果目标对象在另一个线程,必须通过消息队列异步/同步调用。
而且要做到:一个对象只在一个线程被调用,那就是创建该对象的线程!
这样设计,避免了对象的竞争访问和锁的引入,设计对象的时候也不用担心线程安全的问题,
设计逻辑清晰,更容易维护。
2.2 direct
invokeMethod + direct:类似直接调用b->func();
不符合线程安全原则,要避免使用。
2.3 queued
在跨线程的情况下,auto == queued;
如果想要异步调用,也就是只需要把消息发过去,并不关心何时执行完成,使用queued;
如果使用queued调用参数中带有指针,需要保证真正调用后,调用者才释放指针,会比较麻烦,还需要添加一个api告知调用结束。
2.4 blocking
在跨线程的情况下,blocking = queued + wait;
这里的queued表示也会把调用message放到队列中,wait表示直到调用完成返回值,退出调用。
非常适合stop之类的指令:既不会影响目标线程stop之前的任务,也可以保证stop之后目标线程不会继续处理新的任务。
3 源码赏析
3.1 使用场景
* \enum ConnectionType
* \brief Connection type for asynchronous communication
*
* This enumeration describes the possible types of asynchronous communication
* between a sender and a receiver. It applies to Signal::emit() and
* Object::invokeMethod().
在libcamera中,有两种跨线程调用的方法:
① Signal:emit()
// Thread A, class AA
// 绑定
AA.Signal aaSignal_;
aaSignal.connect(B::func);
// 触发
aaSignal.emit(params...);
// Thread B, class BB
// 响应
BB::func(params...)
② Object::invokeMethod()
// Thread A, class AA
AA.bb;
AA.bb->invokeMethod(type, type, params...);
3.2 4种connection type
* \var ConnectionTypeAuto
* \brief If the sender and the receiver live in the same thread,
* ConnectionTypeDirect is used. Otherwise ConnectionTypeQueued is used.
*
* \var ConnectionTypeDirect
* \brief The receiver is invoked immediately and synchronously in the sender's
* thread.
*
* \var ConnectionTypeQueued
* \brief The receiver is invoked asynchronously
*
* Invoke the receiver asynchronously in its thread when control returns to the
* thread's event loop. The sender proceeds without waiting for the invocation
* to complete.
*
* \var ConnectionTypeBlocking
* \brief The receiver is invoked synchronously
*
* If the sender and the receiver live in the same thread, this is equivalent to
* ConnectionTypeDirect. Otherwise, the receiver is invoked asynchronously in
* its thread when control returns to the thread's event loop. The sender
* blocks until the receiver signals the completion of the invocation.
3.3 activatePack 入参和返回值
* \brief Invoke the bound method with packed arguments
* \param[in] pack Packed arguments
* \param[in] deleteMethod True to delete \a this bound method instance when
* method invocation completes
*
* The bound method stores its return value, if any, in the arguments \a pack.
* For direct and blocking invocations, this is performed synchronously, and
* the return value contained in the pack may be used. For queued invocations,
* the return value is stored at an undefined point of time and shall thus not
* be used by the caller.
*
* \return True if the return value contained in the \a pack may be used by the
* caller, false otherwise
异步调用不应该有返回值,因为返回值无意义;
同时异步调用传递的参数也不应该是指针,因为可能会失效!
具体参考: 线程间函数调用
3.4 activatePack
bool BoundMethodBase::activatePack(std::shared_ptr<BoundMethodPackBase> pack, bool deleteMethod)
{
ConnectionType type = connectionType_;
if (type == ConnectionTypeAuto) {
if (Thread::current() == object_->thread())
type = ConnectionTypeDirect;
else
type = ConnectionTypeQueued;
} else if (type == ConnectionTypeBlocking) {
if (Thread::current() == object_->thread())
type = ConnectionTypeDirect;
}
switch (type) {
case ConnectionTypeDirect:
default:
invokePack(pack.get());
if (deleteMethod)
delete this;
return true;
case ConnectionTypeQueued: {
std::unique_ptr<Message> msg =
std::make_unique<InvokeMessage>(this, pack, nullptr, deleteMethod);
object_->postMessage(std::move(msg));
return false;
}
case ConnectionTypeBlocking: {
Semaphore semaphore;
std::unique_ptr<Message> msg =
std::make_unique<InvokeMessage>(this, pack, &semaphore, deleteMethod);
object_->postMessage(std::move(msg));
semaphore.acquire();
return true;
}
}
}
本文来自博客园,作者:moonのsun,转载请注明原文链接:https://www.cnblogs.com/moon-sun-blog/p/19341131

浙公网安备 33010602011771号