Write an EVENT event driver within a cross-platform process

xiaoxiao2021-03-06  109

Well. Before the beginning. I first put me simply on the Event mechanism.

Event is the event, typical is Windows's message, and we often encounter this message when we write a Windows program:

SendMessage (hwnd .....), classic Switch (), through an event mechanism, communication within the process is relaxed, compared to it. UNIX is not so convenient. Although there is msgget and msgsnd Message queue functions, but in Win32, there is no such function.

So. If you want to write some cross-platform procedures, you often have to use third-party libraries such as QT or wxwindow, but I don't like a program, bring a big library, if it is GUI, if It is the command line ... Hey. You have to install X and GTK, etc., compile for a few hours without problems. So we write a simple process drive implementation, save such a large library.

The event driver in the process is mainly three parts. First, the definition event is prepared. The third is the response event. The execution order is based on the principle of FIFO, and the structure is of course a simple stack queue.

Typedef

Struct tagqinn qinn;

Typedef

Struct taginn inn;

Typedef

Struct tagqinnvtbl {

Void (* push) (Qinn * Self,

Void * data);

Void * (* POP) (Qinn * Self);

Void (* Release) (qinn * self);

Qinnvtbl;

Struct Taginn

{

Void * Data;

Struct taginn * pnext;

}

Struct tagqinn

{

Inn * PHEAD;

INN * PTAIL;

QinnvTBL * LPVTBL;

}

// This structure can be found in chamoro.tar.gz.

Provide two functions .POP and PUSH, so you can realize the response of the event.

In addition, our processes are called QEVENT. Let's take a look at the structure first.

TypedEf struct tagqevent qEvent;

TYPEF STRUCT QEVENTVTBL {Int (* self); int (* addevent) (qEvent * Self, int event, void (* evenetfuc)); int (* sendevent) (qEvent * Self, Int Event, void * param; int (* Eventrun); int (* release) (●}}}} QEVENTVTBL; // Original event list TYPEDEF STRUCT TAGQEVENTUNIT {INT M_NEVENTID; VOID (* m_pevenfunc) (void *);} QEventUnit; // event in the queue typedef struct tagQEventDeed {int m_nEvent; void * m_pParam;} QEventDeed; struct tagQEvent {QThread * m_threadEvent; pthread_mutex_t * m_mutexEvent; pthread_cond_t * m_condEvent; pthread_mutex_t * m_mutexUnit; QInn * M_innevent; // Current event list QAUTOLIST * m_ListUnit; // Native event, execute QEventvTBL * LPVTBL;} according to the EventId removal event provided by the event list.

Mainly four functions, we will slowly speak later

Defining events is generally defined in advance, and the function executed by the event is called, it is called Addevent. Put the IDEVENT, such as en_hello first defined. #Define en_hello 110 Because you need to define the pre-definition event to be saved as an original to response List, so that you can find events when you arrive, because we need to save the event (specific QList implementation, you can see the Qlist in Chamoro in Chamoro). I will not repeat it here.

See the implementation of Addevent

QEVENTUNIT * UND = null; assert (self); assert (timefuc); Unt = (qEventUnit *) malloc (sizeof (== null) {return -1;} pthread_mutex_lock (Self-> m_mutexunit) ; Unt-> m_neventid = event; une-> m_pevenfunc = eventfuc; self-> m_listunit-> list.lpvtbl-> add (& self-> m_listunit-> list, us); pthread_mutex_unlock (Self-> m_mutexunit); here we speak The parameter of EventFuc, EventFuc's prototype is in int (* addevent) (qEvent * self, int evenet, void (* evenetfuc) (void *), this is a pointer function Therefore, the declaration of our event response function is general.

Void onhello (Void * param);

This can be startevent after the event is established. It is our ability to receive and respond.

Let's take a look at StartEvent's implementation:

Assert (self); self-> m_threadevent-> lpvtbl-> create (self-> m_threadevent, self-> lpvtbl-> eventrun, self);

Just a sentence, the reason you need to start receiving the thread with startevent, because we have no event response before we have not addevent, so we can flexibly. Hand-to-start should not receive events. (Qthread implementation I apologite behind I)

When StartEvent, you will start a thread. This thread is self-> lpvtbl-> Eventrun, which is the main body of thread run. This function checks if there is no new event. There is a new event to call the corresponding response function. To complete the event driver .

Before eventrun, we still look at int (* sendevent) (qEvent * self, int evenet, void * param); this function is. If you have done Win32 development, you must be unfamiliar with SendMessage. Ha ha. Very familiar. Sendevent's second function is the id, the third is the parameter, if you are multiple parameters, you better use the structure to transfer. Let's see the realization of SendEvent, the code is in front of the code, there is no secret. :)

QEventDeed * deed = NULL; assert (self); deed = (QEventDeed *) malloc (sizeof (QEventDeed)); if (deed == NULL) {return -1;} pthread_mutex_lock (self-> m_mutexEvent); deed-> m_nEvent = event; deed-> m_pParam = param; self-> m_innEvent-> lpVtbl-> Push (self-> m_innEvent, deed); pthread_cond_signal (self-> m_condEvent); pthread_mutex_unlock (self-> m_mutexEvent); ha, is not very Simple? Just a push, gentleman, add it to the stack. It is so simple. :) Of course, still need to lock. See pthread_cond_signal (self-> m_condevent); this sentence. Wait a minute I will know that the source is completed. Of course, I want to inform the main process, there is an incident. Don't sleep: P

Ok. See Eventrun immediately

QEvent * self = (QEvent *) param; QEventUnit * unit; QEventDeed * deed; #ifdef WIN32 // DWORD ThreadID; #endif assert (self); while (TRUE) {pthread_mutex_lock (self-> m_mutexEvent); // if not New events, just waiting for new event if (! Self-> m_innevent-> PHEAD) {pthread_cond_wait (self-> m_condevent, self-> m_mutexevent); pthread_mutex_unlock (Self-> m_mutexevent);

Continue;} else {pthread_mutex_lock (self-> m_mutexunit); // If there is a new event, find an event deed = (qeventdeed *) self-> m_innevent-> lpvtbl-> Pop (Self-> m_innevent); // Find the ID Self-> m_listunit-> list (& self-> m_listunit-> list); unit = (qEventUnit *) Self-> m_listunit-> list.lpvtbl-> getData ( & self-> m_listUnit-> list); while (unit) {if (unit-> m_nEventID == deed-> m_nEvent) {pthread_mutex_unlock (self-> m_mutexEvent); pthread_mutex_unlock (self-> m_mutexUnit); // create a thread or directly Perform a callback function unit-> m_pevenfunc (dEED-> m_pparam); pthread_mutex_lock (self-> m_mutexEvent); pthread_mutex_lock (self-> m_mutexUnit); / * #ifdef WIN32 _beginthreadex (0, 0, (unsigned (__stdcall *) (void *)) unit-> m_pEvenFunc, deed-> m_pParam, 0, & Threadid); #else pthread_create (null, null, unit-> m_pevenfunc, deed-> m_pparam); #ENDIF * / BREAK;} Self-> m_listunit-> list.lpvtbl-> Movenext (& Self-> m_listunit-> list) Unit =

(QEventUnit *) self-> m_listUnit-> list.lpVtbl-> GetData (& self-> m_listUnit-> list);} free (deed); deed = NULL; pthread_mutex_unlock (self-> m_mutexUnit);} pthread_mutex_unlock (self-> m_mutexevent;} return 0; um. It seems that my comments have been written very clear. But one thing, that is, I use / ** / annotation.

/ / Create a thread or directly perform a callback function

This is also the most bad. When you perform a callback function, you will block it, then you will affect other functions. If you use a thread. The price will be too high.

Because my level is limited. I didn't think about a good solution. If you have a good way, you tell me.

OK. Let's introduce here, but we still have to see how to call :)

#include

#define en_hello 100 void onhello (void * param) {char * str = (char *) param; if (str == null) Return; Printf ("Onhello [% s] / n", str);}

INT Main (int Argc, char * argv []) {

INT i = 10; qEvent * Event = mallocqEvent (); event-> lpvtbl-> addevent (Event, en_hello, onhello); event-> lpvtbl-> eventstart (event); event-> lpvtbl-> sendevent (Event, en_hello "This is hello event"; Sleep (1000); event-> lpvtbl-> sendevent (Event, en_hello, "test"); Event-> lpvtbl-> sendevent (Event, en_hello, "test"); Event-> lpvtbl-> WaitquiteVent (event); // If you send a WM_EVENT_OVER, you will wait.

// This line is the paragraph in Win SDK, just triggered the message of WM_QUIT.

// main message loop: while (GetMessage (& MSG, NULL, 0, 0)) {if (! TranslateAccelerator (Msg.hwnd, HaccelTable, & MSG) {TranslateMessage (& MSG); DispatchMessage (& MSG);}}

Just, we are not testing there is no news, and wait for others to tell you, what you want to do. :)

OK. Don't forget this sentence. Event-> lpvtbl-> release (es);}

It is over. This is the first time I wrote such an article, it may not be very clear. If you don't understand, I will get upload code. You look at the code. In addition, Qthread I have already conducted I have encapsulated. I also encapsulated the function and the function of PTHREAD_MUTEX_UNLOCK, but Win32 is encapsulated, or the unix is ​​still used. :)

Bemusedgod

转载请注明原文地址:https://www.9cbs.com/read-96389.html

New Post(0)