2011-12-6 Read 1264Comments1
Always want to learn the design of streaming media server, these days a bit of time, looked at the source code live555. LIVE555 is an open-source, cross-platform streaming media server that uses C + + as a programming language. To summarize the current study notes as follows, the key is to understand the role of several classes and their relationship:
I. Inheritance relationships of the Usageenvironment class and its derived classes
The base class Usageenvironment is an abstract class that defines some interface functions (pure virtual functions) including error code/result message series functions, overloaded output operator series functions, and so on, and defines important data member Fscheduler, It is declared as a reference to TaskScheduler; it is important because it is the engine that the whole program works on. For better encapsulation usageenvironment the constructors and destructors are declared as protected. As you'll see later, the construction of the derived class of usageenvironment is implemented through the static function Creatnew, and the destructor is implemented by calling the Reclain () function.
BasicUsageEnvironment0 is simple, it defines a character array to store the result message, just implements the result message series function in Usageenvironment, so it is still an abstract class.
Basicusageenvironment is also very simple, it implements the overload of the output operator series function and the static function Creatnew.
So just remember these three things: the result message function, the output operator function, the TaskScheduler reference variable, you can understand the role of usageenvironment and its derived classes. It can actually be represented by a total of three classes, and the author may have put them together for ease of use. Because when we want to add functionality to the program, can be completed in TaskScheduler, but want to set and output the program during the running of the message, you can directly use the output operator and the result message processing function, it provides a good environment for the subsequent development of the program.
Two. Inheritance relationships for TaskScheduler classes and their derived classes
As the name implies, TaskScheduler is a task scheduler. Its inheritance diagram is similar to Usageenvironment, hehe, with the previous analysis we should also be easy to master this class. The task here is abstract and can be imagined as a piece of code or a function, and the purpose of task scheduling is to determine which task the program should currently run.
1.TaskScheduler is an abstract base class that defines a series of interface functions, where doeventloop is defined as a program loop function. Depending on the category of the task, the author is divided into three categories, each of which completes the invocation in the following order (refer to the SingleStep function in Basictaskscheduler):
(1) The first processing is the socket Event, which is responsible for I/O multiplexing, using the Select function to wait for the specified description word to be ready for reading, writing, or exception handling. If the Select return value is greater than-1, it goes to the appropriate handler, otherwise it indicates an exception and the program goes to the error-handling code. This type is suitable for tasks that have I/O operations.
Correlation function: setbackgroundhandling/disablebackgroundhandling/movesockethandling
(2) the trigger event (trigger-event) is then processed. The author defines a 32-bit bitmap to implement the triggering event, and when one is set to 1 it indicates that the event to which the bit corresponds is to be triggered. If there are multiple (3 or more) triggering events at the same time, their triggering will also be related to the order in which the event was created, so this type is only appropriate for tasks that do not have a sequential dependency relationship.
Correlation function: createeventtrigger/deleteeventtrigger/triggerevent
(3) The last one is a deferred task (Delayed tasks), which is a task with time. When the remaining time is not 0, the task does not execute. You can flexibly schedule tasks by adjusting the remaining time of the task.
Correlation function: Scheduledelayedtask/unscheduledelayedtask/rescheduledelayedtask
TaskScheduler also retains the turnonbackgroundreadhandling/turnoffbackgroundreadhandling function in order to be compatible with previous programs, In fact, they are also implemented by invoking Setbackgroundhandling/disablebackgroundhandling. Of course, there is also an error handler Interalerror, handler error, derived classes can be overloaded.
The 2.BASICTASKSCHEDULER0 primarily implements trigger events and delayed tasks.
(1) The trigger event is implemented by a 32-bit graph, which uses two arrays to store function pointers and function parameter pointers that trigger events. It is stored from the highest, that is, the No. 0 element of the highest bit corresponding function pointer array and the parameter pointer array, which can use up to 32 triggers. It also holds the last triggered sequence number and trigger mask as the next starting point, ensuring that all triggers are triggered.
(2) The deferred task is implemented through a two-way circular linked list. Its nodes are actually Alarmhandler, and the linked list is implemented as Delayqueue, which are inherited from the Delayqueueentry base class, and the relationships between the three are as follows:
Delayqueueentry can be seen as a node in an abstract doubly linked list, with the exception of forward pointers and back pointers, which attach a fdeltatimeremaining member and Ftoken member, which represents the delay time and the unique flag that identifies the node. It also defines the virtual function handletimeout () that is called when there is a timeout.
Alarmhandler is the actual delay task node, very simple, it defines a function pointer and function parameter pointer on the basis of Delayqueueentry, and overloads the Handletimeout function.
Delayqueue is a loop linked list class, generally without inheriting delayqueueentry, the author here is to use it as the head node of the circular list. The rest is the regular operation of the circular list, including the query, insert, delete, update operation of the node. Delayqueue also implements the Timetonextalarm () return head node delay, and handlealarm () actual delay task processing, the actual call is the node's handletimeout () function;
The 3.BasicTaskScheduler class implements the remaining I/O operations task interface and the actual scheduling of three types of tasks (the SingleStep function).
The implementation of the I/O task is also simple, and it also uses a bidirectional circular list to store tasks. Its nodes are defined as Handlerdiscriptor, including front-to-back node pointers, function pointers and function parameter pointers, and IO-related socketnum and Conditionset data members. The circular list class is defined as Handlerset, which similarly defines the query, insert, delete, and update operations. It declares a node member as the head node.
Three. Testing of the Usageenvironment
Now that you can test the functionality of these classes, I've written a simple program that sets up three types of tasks and dispatches them. The code is as follows:
This was a test for basic objects, such as Taskschduler, and Usageenvironment and//so on. It ' s just for study purpose. #include <BasicUsageEnvironment.hh> #include <iostream>using namespace std; taskscheduler* Scheduler = Basictaskscheduler::createnew (); usageenvironment* env = basicusageenvironment::createnew (*scheduler); void Taskfunc (void* clientdata) {cout<< " Taskfunc (\ "<< (char*) clientdata<<" \ ") called." <<endl;} void Handlerfunc (void* clientdata, int mask) {cout<< "Handlerfunc (\" "<< (char*) clientdata<<" \ "," <<mask<< ") called." <<endl;scheduler->disablebackgroundhandling (Stdout_fileno);} int main (int argc, char* args[]) {//IO event Test char handlerclientdata[] = "IO event"; Scheduler->setbackgroundhandling (Stdout_fileno, socket_writable, (taskscheduler::backgroundhandlerproc*) & Handlerfunc, Handlerclientdata); Trigger Event Test Eventtriggerid ID1 = Scheduler->createeventtrigGER (Taskfunc); Char triggerclientdata1[] = "Trigger Event 1"; Eventtriggerid Id2 = Scheduler->createeventtrigger (Taskfunc); Char triggerclientdata2[] = "Trigger Event 2"; Eventtriggerid ID3 = Scheduler->createeventtrigger (Taskfunc); Char triggerclientdata3[] = "Trigger Event 3";(*env) << "Setting event triggers...\n"; Scheduler->triggerevent ( Id2, (void*) triggerClientData2); Scheduler->triggerevent (ID1, (void*) triggerClientData1); Scheduler->triggerevent (ID3, (void*) triggerClientData3); (*env) << "Event triggers has been set.\n";//Delayed task Testchar delayedtaskclientdata1[] = "delayed task 1s"; Tasktoken token1 = Scheduler->scheduledelayedtask (1000000,taskfunc, delayedTaskClientData1); char Delayedtaskclientdata2[] = "Delayed Task 5s"; Tasktoken token2 = Scheduler->scheduledelayedtask (5000000, Taskfunc, Delayedtask CLIENTDATA2);//Loopscheduler->doeventLoop (); return 0;} Compile execution, the result of the output is: Setting Event triggers ...
Event triggers has been set.
Handlerfunc ("IO Event", 4) called.
Taskfunc ("Trigger Event 1") called.
Taskfunc ("Trigger Event 2") called.
Taskfunc ("Trigger Event 3") called.
Taskfunc ("Delayed Task 1s") called.
Taskfunc ("Delayed Task 5s") called. The code works correctly.
Summarize:
LIVE555 uses the Usageevironment class and Tasksheduler classes, and their derived classes, to build a good program development infrastructure that can be easily built on our various applications. A task takes only two steps to complete, defining task handlers based on the type of task, and then adding the task to the loop body.
It is important to note the performance and thread safety issues of this Task Scheduler. If a task takes a long time to process or block, then the main loop will also be blocked, other tasks will not be timely response, so the design task to consider the time spent on the task, if too long to consider whether to open up another thread to process. Also, from the source code, the Task Scheduler does not do more work to support multithreading, so adding tasks through multiple threads can cause exceptions.
Transferred from: http://m.blog.csdn.net/blog/huangwanzhang/7042843
(GO) live555 Learning notes-usageenvironment and TaskScheduler