From 670f56e165b97b23ec9895c9a5d0f0673908691c Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Sat, 11 Oct 2003 04:43:55 +0000 Subject: [PATCH] Se agrega el codigo fuente del thread con objetos modificado para pthreads. --- docs/oo_callbacks_cpp/oo_callbacks_cpp.html | 394 ++++++++++---------- tests/oo_thread.cpp | 140 +++++++ 2 files changed, 337 insertions(+), 197 deletions(-) create mode 100644 tests/oo_thread.cpp diff --git a/docs/oo_callbacks_cpp/oo_callbacks_cpp.html b/docs/oo_callbacks_cpp/oo_callbacks_cpp.html index 5eaa828..839e513 100644 --- a/docs/oo_callbacks_cpp/oo_callbacks_cpp.html +++ b/docs/oo_callbacks_cpp/oo_callbacks_cpp.html @@ -1,197 +1,197 @@ - - -Callbacks in C++: The OO Way - - - - - - - - -
C-Scene Issues 1..9 Authors
Algorithms Books Patterns Graphics Miscellaneous UNIX Web & XML Windows
Feedback FAQs Changes Submissions
-
-

Callbacks in C++: The OO Way

-
-

Content

-
    -
  1. What are - Callbacks? -
  2. A simple - Thread class -
  3. Thread - implementation -
  4. A real - Thread class
-
-

by Jürgen Hermann
last updated 2001/08/02 (version -1.1.1.1)
also available as XML

-
-

What are Callbacks?

-

Many operating systems and other subsystems (like GUI libraries) feature a -special type of hook into those systems, named callbacks or callback functions. -Upon initialization or by calling an API function you pass pointers to the -callback into the subsystem, for later use. The problem with those functions is, -since these subsystems are nowadays not yet OO, that they have no notion of what -an object is. So if you want to have a callback object  instead of -a mere function, some OO magic is called for.

-

As an example, consider the BeginThread API that many OSes have -in a quite similar form; we assume that it takes a pointer to the function that -provides the actual code for the newly created thread plus a data -pointer  that is passed to that function as a startup parameter. Thus, -we end up with BeginThread (void (*thread_func) (void*), void* -startup_data). Now let's make a Thread class of -that.

-
-

A simple Thread class

-

What we want to have is an ABC (abstract base class) that you can inherit -from, creating specialized thread classes and in turn thread objects (i.e. -actual threads). The code of the thread is located in a pure -virtual  function code that is provided by the inherited -class. code is then similar to the thread_func -parameter of the BeginThread call, but is a full-blown member -function, not just a C function. So, we get this interface for the -Thread class:

class Thread {
-public:
-    virtual ~Thread();
-    void run();
-
-protected:
-    Thread();
-    virtual void code() = 0;
-
-private:
-    int running;
-
-    static void dispatch(void* thread_obj);
-};
-
-

This might seem quite unusual to you (like having a protected constructor), -but things will be explained in due course.

-
-

Thread implementation

-

When we put the thread concept into a class, we have to consider lifetime. A -thread exists as long as the thread function does not return, thus the object -has to have the same lifetime. Because of this, an auto thread -object does not make much sense; we insure that every thread object exists on -the heap by making the ctor protected and providing a static factory method -create for thread objects in each derived class:

Thread::Thread() 
-    : running(0) 
-{
-}
-
-DerivedThread& DerivedThread::create()
-{
-    return *new DerivedThread;
-}
-
-

create has to be added to every inherited class, returning an -object of that class.

-

Next, we need a run method that actually starts the thread. This -can't be done in the ctor: when code would be registered as a -thread of execution in the base class  ctor, the superclass would -not yet be fully created and calling code would be quite invalid -and dangerous. run does its job by registering the -dispatch function as a thread, giving that thread the object -pointer as a startup parameter; since dispatch is static, it has a -prototype that matches the void(*)(void*) parameter of -BeginThread.

void Thread::run()
-{
-    // Don't start two threads on the same object
-    if (running) return;
-
-    // Create an OS thread, using the static callback
-    BeginThread(Thread::dispatch, this);
-    running = 1;
-}
-
-

So finally, dispatch is called and performs the step from a -procedural callback to the callback object:

void Thread::dispatch(void* thread_obj)
-{
-    // Call the actual OO thread code
-    ((Thread*)thread_obj)->code();
-
-    // After code() returns, kill the thread object
-    delete (Thread*)thread_obj;
-}
-
-
-

A real Thread class

-

A real-world thread class has to consider a few things we have ignored here. -These things include:

-
    -
  1. more access to the thread data, like a method giving the thread ID. -
  2. a method for killing the thread, including the deletion of the thread - object.
-

Developed and tested on Windows NT, this is the source for a little -example program that implements the above in the real world. If you run it, you -get something similar to the following output:

[\cscene\callback]callback
-Started thread #80 for dice1
-Started thread #84 for dice2
-dice1 rolled 1
-dice2 rolled 1
-dice2 rolled 3
-dice1 rolled 1
-dice2 rolled 4
-dice1 rolled 6
-dice1 rolled 3
-dice2 rolled 3
-dice1 rolled 1
-dice1 rolled 4
-dice2 rolled 4
-dice2 rolled 3
-dice1 rolled 1
-dice2 rolled 6
-dice1 rolled 2
-dice2 rolled 2
-dice1 rolled 1
-dice2 rolled 4
-dice2 rolled 1
-dice1 rolled 4
-dice1 rolled 5
-dice2 rolled 1
-dice1 rolled 3
-dice2 rolled 3
-dice1 rolled 2
-dice1 rolled 6
-dice2 rolled 2
-dice1 rolled 1
-dice2 rolled 3
-dice1 rolled 4
-dice1 rolled 5
-dice2 rolled 3
-dice2 rolled 6
-dice1 rolled 4
-
-

Have fun!

-

This article is Copyright © 1997-98 by Jürgen Hermann
and -Copyright © 1999 by C-Scene. All Rights Reserved.

-
-
-Copyright © 1997-2000 by C-Scene. All Rights Reserved.

Part of the -graphics and stylesheets used to generate this site are
Copyright © 1999-2000 -by Apache Software Foundation.
+ + +Callbacks in C++: The OO Way + + + + + + + + +
C-Scene Issues 1..9 Authors
Algorithms Books Patterns Graphics Miscellaneous UNIX Web & XML Windows
Feedback FAQs Changes Submissions
+
+

Callbacks in C++: The OO Way

+
+

Content

+
    +
  1. What are + Callbacks? +
  2. A simple + Thread class +
  3. Thread + implementation +
  4. A real + Thread class
+
+

by Jürgen Hermann
last updated 2001/08/02 (version +1.1.1.1)
also available as XML

+
+

What are Callbacks?

+

Many operating systems and other subsystems (like GUI libraries) feature a +special type of hook into those systems, named callbacks or callback functions. +Upon initialization or by calling an API function you pass pointers to the +callback into the subsystem, for later use. The problem with those functions is, +since these subsystems are nowadays not yet OO, that they have no notion of what +an object is. So if you want to have a callback object  instead of +a mere function, some OO magic is called for.

+

As an example, consider the BeginThread API that many OSes have +in a quite similar form; we assume that it takes a pointer to the function that +provides the actual code for the newly created thread plus a data +pointer  that is passed to that function as a startup parameter. Thus, +we end up with BeginThread (void (*thread_func) (void*), void* +startup_data). Now let's make a Thread class of +that.

+
+

A simple Thread class

+

What we want to have is an ABC (abstract base class) that you can inherit +from, creating specialized thread classes and in turn thread objects (i.e. +actual threads). The code of the thread is located in a pure +virtual  function code that is provided by the inherited +class. code is then similar to the thread_func +parameter of the BeginThread call, but is a full-blown member +function, not just a C function. So, we get this interface for the +Thread class:

class Thread {
+public:
+    virtual ~Thread();
+    void run();
+
+protected:
+    Thread();
+    virtual void code() = 0;
+
+private:
+    int running;
+
+    static void dispatch(void* thread_obj);
+};
+
+

This might seem quite unusual to you (like having a protected constructor), +but things will be explained in due course.

+
+

Thread implementation

+

When we put the thread concept into a class, we have to consider lifetime. A +thread exists as long as the thread function does not return, thus the object +has to have the same lifetime. Because of this, an auto thread +object does not make much sense; we insure that every thread object exists on +the heap by making the ctor protected and providing a static factory method +create for thread objects in each derived class:

Thread::Thread() 
+    : running(0) 
+{
+}
+
+DerivedThread& DerivedThread::create()
+{
+    return *new DerivedThread;
+}
+
+

create has to be added to every inherited class, returning an +object of that class.

+

Next, we need a run method that actually starts the thread. This +can't be done in the ctor: when code would be registered as a +thread of execution in the base class  ctor, the superclass would +not yet be fully created and calling code would be quite invalid +and dangerous. run does its job by registering the +dispatch function as a thread, giving that thread the object +pointer as a startup parameter; since dispatch is static, it has a +prototype that matches the void(*)(void*) parameter of +BeginThread.

void Thread::run()
+{
+    // Don't start two threads on the same object
+    if (running) return;
+
+    // Create an OS thread, using the static callback
+    BeginThread(Thread::dispatch, this);
+    running = 1;
+}
+
+

So finally, dispatch is called and performs the step from a +procedural callback to the callback object:

void Thread::dispatch(void* thread_obj)
+{
+    // Call the actual OO thread code
+    ((Thread*)thread_obj)->code();
+
+    // After code() returns, kill the thread object
+    delete (Thread*)thread_obj;
+}
+
+
+

A real Thread class

+

A real-world thread class has to consider a few things we have ignored here. +These things include:

+
    +
  1. more access to the thread data, like a method giving the thread ID. +
  2. a method for killing the thread, including the deletion of the thread + object.
+

Developed and tested on Windows NT, this is the source for a little +example program that implements the above in the real world. If you run it, you +get something similar to the following output:

[\cscene\callback]callback
+Started thread #80 for dice1
+Started thread #84 for dice2
+dice1 rolled 1
+dice2 rolled 1
+dice2 rolled 3
+dice1 rolled 1
+dice2 rolled 4
+dice1 rolled 6
+dice1 rolled 3
+dice2 rolled 3
+dice1 rolled 1
+dice1 rolled 4
+dice2 rolled 4
+dice2 rolled 3
+dice1 rolled 1
+dice2 rolled 6
+dice1 rolled 2
+dice2 rolled 2
+dice1 rolled 1
+dice2 rolled 4
+dice2 rolled 1
+dice1 rolled 4
+dice1 rolled 5
+dice2 rolled 1
+dice1 rolled 3
+dice2 rolled 3
+dice1 rolled 2
+dice1 rolled 6
+dice2 rolled 2
+dice1 rolled 1
+dice2 rolled 3
+dice1 rolled 4
+dice1 rolled 5
+dice2 rolled 3
+dice2 rolled 6
+dice1 rolled 4
+
+

Have fun!

+

This article is Copyright © 1997-98 by Jürgen Hermann
and +Copyright © 1999 by C-Scene. All Rights Reserved.

+
+
+Copyright © 1997-2000 by C-Scene. All Rights Reserved.

Part of the +graphics and stylesheets used to generate this site are
Copyright © 1999-2000 +by Apache Software Foundation.
diff --git a/tests/oo_thread.cpp b/tests/oo_thread.cpp new file mode 100644 index 0000000..9b03685 --- /dev/null +++ b/tests/oo_thread.cpp @@ -0,0 +1,140 @@ +// Callbacks in C++ +// Refer to http://www.cscene.org for detailed docs. +// +// Copyright (c) 1998 by Juergen Hermann +// +// To make things easy, we put all code in one file. +// Large parts of this should go to thread.hpp/cpp in real real life. + +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////// +// Utility stuff +/////////////////////////////////////////////////////////////////////// + +inline int randrange(int lo, int hi) +{ + return rand() / (RAND_MAX / (hi - lo + 1)) + lo; +} + + +/////////////////////////////////////////////////////////////////////// +// A thread base class +/////////////////////////////////////////////////////////////////////// + +class Thread { +public: + virtual ~Thread() {} + void run(); + pthread_t get_thread() const { return thread; } + +protected: + Thread(); + virtual void code() = 0; + +private: + int running; + pthread_t thread; + + static void* dispatch(void* thread_obj); +}; + + +Thread::Thread() + : running(0) +{ +} + + +void Thread::run() +{ + // Don't start two threads on the same object + if (running) return; + + // Create an OS thread, using the static callback + assert(!pthread_create(&thread, NULL, Thread::dispatch, static_cast(this))); + pthread_detach(thread); + running = 1; +} + + +void* Thread::dispatch(void* thread_obj) +{ + // Call the actual OO thread code + static_cast(thread_obj)->code(); + + // After code() returns, kill the thread object + delete static_cast(thread_obj); + + return NULL; +} + + +/////////////////////////////////////////////////////////////////////// +// An example thread class +/////////////////////////////////////////////////////////////////////// + +class Dice : private Thread { +public: + static void Dice::create(const char* dicename); + //static CRITICAL_SECTION sync; + +private: + Dice(const char* dicename) : name(dicename) {} + virtual void code(); + + std::string name; +}; + + +//CRITICAL_SECTION Dice::sync; + + +void Dice::create(const char* dicename) +{ + (new Dice(dicename))->run(); +} + + +void Dice::code() +{ + //EnterCriticalSection(&sync); + std::cout << "Started thread #" << static_cast(get_thread()) + << " for " << name << std::endl; + //LeaveCriticalSection(&sync); + + srand(time(0) * get_thread()); + + for (;;) { + int val = randrange(1, 6); + + //EnterCriticalSection(&sync); + std::cout << name << " rolled " << val << std::endl; + //LeaveCriticalSection(&sync); + + sleep(randrange(0, 1)); // wait up to 1 sec + } +} + + +/////////////////////////////////////////////////////////////////////// +// Let's test! +/////////////////////////////////////////////////////////////////////// + +int main() +{ + //InitializeCriticalSection(&Dice::sync); + + Dice::create("dice1"); + Dice::create("dice2"); + + sleep(10); // roll dice for 10 seconds + + return 0; // cleanup? what's cleanup? +} -- 2.43.0