Implementing signal and slot mechanisms (2)-cross-thread delivery

Source: Internet
Author: User

Objective

In 1, we implemented a basic Signal+slot module invocation mechanism, but that direct call, in this case, we will support the Kua-thread invocation, the function that invokes the object in the context of the object's thread.

Object Thread Binding

In Qt, there is a very important concept, object thread binding, that is, at each object instance, it holds its thread context information, there is an event loop, the cross-thread signal is to throw this task into the event loop, the object bound in the thread to complete the slot response.

Implementing a package-task for a slot call

We need to package a cross-thread slot call into a task and throw it into a corresponding event loop. A task queue needs to be maintained in the event loop, which is the first container to be made.

struct TaskBase{    virtual0;    virtualvoid0;};TaskBase::~TaskBase(){}

TaskBaseFor our task base class, in the event loop, maintain one of its linked lists.
We inherit it and implement our first task, a general task.

Template <typename Method>struct normaltask :  PublicTaskbase{typedef typename PARAMETERTUPLETRAITS<PARAMETERTRAITS<METHOD>>::P arameters Parameters; typedef typename TYPETRAITS<TYPENAME Parametertraits<method>::classtype_value>::p ointertype_value type    _value;                                                                Normaltask (Type_value object, Method m, Parameters paras): Taskbase (),                                                                M_object (object), M_method (m), M_paras (paras) {}    Virtual~normaltask (){}void Run (){printf ("run:%lu\n", Pthread_self ());    Impledotask (M_object, M_method, M_paras); }Type_value M_object; Method m_method;Parameters M_paras;};

In fact, a template is related to specific object member functions, accept, object pointers, object member function pointers and parameters. Pthread_self can print the identity of the current thread, in fact a unsigned long type number, here in order to see its execution thread.

Event loops and Object bindings

In order to implement object thread binding, we must provide a base class on this system, just like the Qobject in Qt.

struct Box{    Box()    {        m_loop = EventLoop::currentEventLoop();    }    EventLoop *m_loop;};

Below the beginning of our event loop, in fact, this only a task queue, in reality, it must also be able to listen to various events in the system, such as the button, mouse, Gachiva to the appropriate object, is my blog about the event monitoring distribution, there is no discussion here.

 StaticEventLoop *currenteventloop () {EventLoop *re = NULL; pthread_t pid = pthread_self ();STD:: map<pthread_t, EventLoop *>:: Iterator ite = S_eventloops.find (PID);if(Ite! = S_eventloops.end ())        {re = ite->second; }Else{re =NewEventLoop (PID); S_eventloops.insert (STD::p air<pthread_t, EventLoop *> (PID, re)); }returnRe }Static void Exit()    { for(Autoite = S_eventloops.begin (); Ite! = S_eventloops.end (); ++ite) {ite->second->quit ();Delete(Ite->second);    } s_eventloops.clear (); }intEXEC () { while(run) { for(Autoite = M_tasks.begin ();            Ite! = M_tasks.end ();) {(*ite)->run ();Delete(*ite);            ite = M_tasks.erase (ITE); }//sleep (ten);}return 1; }voidQuit () {run =false; }};STD:: map<pthread_t, EventLoop *>Eventloop::s_eventloops =STD:: map<pthread_t, EventLoop *>();
How to implement Delivery

Provides an enumeration to set the connection type

enumCONNECT_TYPE{    SYNC,    AYNC,    AUTO};

Correspondence: Synchronous, asynchronous and system-determined.
In the original signal Eemit, we must achieve the difference between sending

 voidEemit () {printf ("eemit:%lu\n", Pthread_self ());STD::tuple<> para; for(TypeNameListvalue_type:: Iterator ite = Sloters.begin (); Ite! = Sloters.end (); ++ite) {Connect_type Type = (*ite)M_type;Switch(type) { Case SYNC:            {if  (eventloop::currenteventloop () = = ((*ite)->eventloop ())) { (*ite) ->Dotask (para); }Else{ (*ite)EventLoop ()Postnormaltask(  (*ite)->convertanormaltask (para));            }            };            break;  Case Aync: { (*ite)EventLoop ()Postnormaltask(  (*ite)->convertanormaltask (para));            };            break;  Case AUTO: { if (eventloop::currenteventloop () = = ((*ite)->eventloop ()) ) { (*ite)Dotask (para); }Else{ (*ite)EventLoop ()Postnormaltask(  (*ite)->convertanormaltask (para));            }            };            break;            default: break; }        }    }

In order to differentiate the behavior in eemit based on the thread binding of the object, but we get the object is just a base class pointer, so the original base class was modified.

template <typename Paras>struct SlotBase{    SlotBase(CONNECT_TYPE type) : m_type(type)    {    }    virtual0;    virtual0;    virtual0;    virtualvoid0;    CONNECT_TYPE m_type;};template <typename Paras>SlotBase<Paras>::~SlotBase(){}

In the slot implementation of this even a pure virtual function, to get the packaged task and get the slot object of the event loop pointer.

  *convertAnormalTask(Parameters paras)    {        return new NormalTask<M>(m_object, m_method, paras);    }    *eventloop()    {        return m_object->m_loop;    }

This ensures that the correct task and event loops are obtained at eemit, and when the objects of the EventLoop and Eemit of the slot objects are not in one thread, we post the task to the eventloop of the slot object.
In order to achieve the following use

    *loop= EventLoop::currentEventLoop();    loop->postNormalTask(NewNormalTask(&&A::func_b1314));

We have Newnormaltask versions available

Template <typenameMethod>Taskbase*Newnormaltask (TypeName typetraits<typename parametertraits<Method  >::classtype_value>::p Ointertype_value object, method M, TypeName Parametertraits<method ;::P 0 p0, TypeName Para Metertraits<method ;::P 1 P1, TypeName PARAMETERTRAITS<
      
       method 
      ;::P 2 P2, typename Parametertraits<method "::P 3 P3, typename Parametertraits<method>::P 4 P4, TypeName Parametertraits<method ;::P 5 p5) {staticcheck<parametertraits<method>::size = = 6> A;    Unuse (a); TypeName Parametertupletraits<parametertraits<method>>::P arameters paras = std::make_tuple (P0, p1, p2, p3    , P4, p5); return new Normaltask<method> (object, M, paras);}
Application examples
#include <iostream>#include "signal.h"using namespace STD;structttt{intAintbintc;};classN: Publicbox{ Public:Virtual voidFunc_c (intAintb) =0;};classA: Publicn{ Public: A () {S1.connect ( This, &a::func_ii); }voidFunc_b (intA) {cout<< a <<"aaaaaa\n";}voidFunc_c (intAintb) {cout<< a <<"+"<< b <<"="<< a+b <<STD:: Endl;}voidFunc_a () {TTT T = {1,' s ',' t '};    S.eemit (T, T, T); }voidFunc_i () {int*i =New int(1);    S1.eemit (i); }voidFunc_ii (int*i) {cout<< *i; (*i) + +;DeleteI }voidFunc_z () {cout<<"Zhou Xiang"; } signal<void(*)    (TTT, TTT, TTT) > s; signal<void(*) (int*) > S1;};classD | Publicbox{ Public: B (A *a): M_a (a) {} B () {}voidFunc_b (intA) {cout<< a <<"bbbbbbb\n";}voidFunc_slot (TTT T, TTT T2, TTT T3) {cout<< t.a + t2.b + t3.c <<"-==-=-=-==-=\n"; }voidFunc_z () {cout<<"Love chenchen\n"; } A *m_a;voidFunc_e () {M_a->s.connect ( This, &b::func_slot); }};void* Pt_callback (void* arg) {A AA;    B BB; signal<void(*) () > *s = (signal<void(*)    () >*) (ARG);    S->connect (&AMP;AA, &a::func_z);    S->connect (&AMP;BB, &b::func_z);    EventLoop *loop = Eventloop::currenteventloop (); Loop->exec ();returnNULL;}intMain () {A object;    B Object1 (&object); signal<void(*) (int,int) > S; signal<void(*) () > SSSs;//Ssss.connect (&object, &a::func_z);    //Ssss.connect (&object1, &b::func_z);    //Ssss.connect (&object1, &b::func_z);//S.connect (&object, &a::func_c);//S.connect (&object, &a::func_c);//S.connect (&object, &a::func_c);//S.connect (&object, &a::func_c);//S.connect (&object, &a::func_c);//S.connect (&object, &a::func_c);//S.connect (&object, &a::func_c);//Object1.func_e ();//Object1.func_e ();//Object.func_a ();    //ssss.eemit ();    //Ssss.disconnect (&object, &a::func_z);    //Ssss.disconnect (&object1, &b::func_z);    //object.func_i ();    //cout << "---------------------------\ n";    //ssss.eemit ();    //s.eemit (4, 456);    //EventLoop *loop = Eventloop::currenteventloop ();    //Loop->postnormaltask (Newnormaltask (&object, &a::func_b, 1314));    //std::cout << "+++++++++++++++++++++\n";pthread_t Ptid;intPtre = Pthread_create (&ptid, NULL, Pt_callback, (void*) (&AMP;SSSS));if(Ptre! =0)    {printf("Dispatcher thread create fail!\n"); } ssss.eemit ();//Ssss.disconnect (&object, &a::func_z);    //Ssss.disconnect (&object1, &b::func_z);    //object.func_i ();    cout<<"---------------------------\ n";    Ssss.eemit ();    EventLoop *loop = Eventloop::currenteventloop (); Loop->postnormaltask (Newnormaltask (&object, &a::func_b,1314)); Loop->exec ();return 0;}

Run results

There is no lock during operation of the queue. There is a thread between the execution is not controllable, in the Eemit, in the Pt_callback, Connect has not completed, resulting in, sometimes there are two responses sometimes one, the thread to the standard output is also not controllable when writing, all log a bit ugly, but still explain the problem, The action is made in the thread-up-and-down of an object.

The project code can find the address in 1.

Implementing signal and slot mechanisms (2)-cross-thread delivery

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.