02. Sending This Pointer

How to use this pointer in class

DesignPattern

Usages

  • How to use this pointer as an argument of callback function
  • How to use this pointer as a static member variable.
  • How to make a library with this pointer

Explain

Callback with this argument

Generally, OS provides a C API to control threads. Code 1 shows a simple traditional C++ example (C++98/03) to create a thread with a callback function in Linux.

// 01_C_testThread.cpp
#include <iostream>

#include <pthread.h>

using namespace std;

void* foo(void *p)
{
    string* str = static_cast<string*>(p);
    cout << str->c_str() << endl;

    return NULL;
}

int main() {
    pthread_t tid;
    string str = "Thread Start";

    // Create thread
    pthread_create(&tid, NULL, foo, static_cast<void*>(&str));

    // Wait for thread
    pthread_join(tid, NULL);

    cout << "Thread id: " << tid << endl;
    return 0;
}
// Compile: clang++ -pthread
//          -o 01_C_testThread 01_C_testThread.cpp
Code 1. C API for thread
Thread Start
Thread id: 140625819205632

When Code 1 is executed, pthread_create(), which is a C API, creates a thread. Then, the thread executes foo() to print "Thread start". It works fine, but it is not easy to use pthread_create() for a user. The user should know what the all arguments are, even though the user does not need special handling for a thread. If there is a library for thread and it wraps pthread_crate () with single exposed argument for callback, the user can easily create thread.

In this case, it is important to use a static member function as a callback. Because pthread_create() is a C API and it does not know which instance is a target, it can only call a static member function. Fortunately, The fourth argument of pthread_create() is an argument for the callback, so it is possible to pass this pointer of an instance. With this pointer, the callback can specify which instnace is a target. Code 2 shows how to make a thread library and use it.

// 02_C_testThreadInClass.cpp
#include <iostream>

#include <pthread.h>

using namespace std;

// Library
class ThreadLib
{
private:
    pthread_t tid;

public:
    ThreadLib()
    : tid(0)
    {}

    void run()
    {
        // Create thread
        pthread_create(&tid, NULL, _threadLoop, this);

        // Wait for thread
        pthread_join(tid, NULL);
        cout << "Thread id: " << tid << endl;

        return;
    }

    static void* _threadLoop(void* p)
    {
        ThreadLib* const self = static_cast<ThreadLib*>(p);

        self->threadLoop();     // threadLoop(self)

        return NULL;
    }

    virtual bool threadLoop()
    {
        cout << "ThreadLib's threadLoop" << endl;

        return false;
    }
};

// User defined library
class MyThreadLib : public ThreadLib
{
    virtual bool threadLoop()
    {
        cout << "MyThreadLib's threadLoop" << endl;

        return true;
    }
};

int main()
{
    MyThreadLib t;

    t.run();                    // Thread is created and
                                // threadLoop() of MyThreadLib is executed

    return 0;
}
// Compile: clang++ -pthread
//          -o 02_C_testThreadInClass 02_C_testThreadInClass.cpp
Code 2. Thread Library
MyThreadLib's threadLoop
Thread id: 139854596114176

_threadLoop() is a static member function, and it has argument p for this. P is converted to ThreadLib class pointer, and it calls threadLoop(), which is overrided by an user's class. Therefore, only thing user have to do is to make threadLoop() with a function what he/she wants.

Callback without this argument

How about the callback function having no redundant argument? Code 3 shows a simple example for a callbak whose arguments are reserved.

// 03_C_testTimer.cpp
#include <iostream>
#include <vector>

#include <unistd.h>
#include <pthread.h>

using namespace std;

typedef pair<pthread_t, int> Timer;
void* foo(void *p)
{
    // Get timer information
    Timer* timer = static_cast<Timer*>(p);

    // Wait
    sleep(timer->second);

    cout << "Thread id: " << timer->first
            << ", time: " << timer->second << endl;

    return NULL;
}

Timer* setTimer(int _time, void* (*func)(void *))
{
    Timer* timer = new Timer();
    timer->second = _time;

    // Create thread
    pthread_create(&(timer->first), NULL, func, static_cast<void*>(timer));

    return timer;
}

typedef vector<Timer *>::iterator TIterator;
void waitTimer(vector<Timer *>& timer)
{
    for (TIterator tItr = timer.begin(); tItr != timer.end(); ++tItr)
    {
        // Wait for thread
        pthread_join((*tItr)->first, NULL);

        // Clear memory
        delete *tItr;
        *tItr = NULL;
    }
}

int main()
{
    vector<Timer*> timers;

    // Set timer
    timers.push_back(setTimer(10, foo));
    timers.push_back(setTimer(5, foo));

	waitTimer(timers);

	return 0;
}
// Compile: clang++ -pthread
//          -o 03_C_testTimer 03_C_testTimer.cpp
Code 3. Normal callback function
Thread id: 140388092651264, time: 5
Thread id: 140388101043968, time: 10

setTimer() sets a timer with a callback function and returns a pointer for a pair of thread id and setting time. WaitTimer() sets a barrier for threads and deletes allocated memory for timer. However, setTimer() does not have an argument to send this pointer. In this case, a container is necessary to hold a pair of an thread id and this pointer for instance. Code 4 shows how setTimer() and waitTimer () are wrapped up in a class.

// 04_C_testTimerForId.cpp
#include <iostream>
#include <map>
#include <vector>

#include <unistd.h>
#include <pthread.h>

using namespace std;

typedef pair<pthread_t, int> Timer;

Timer* setTimer(int _time, void* (*func)(void *))
{
    Timer* timer = new Timer();
    timer->second = _time;

    // Create thread
    pthread_create(&(timer->first), NULL, func, static_cast<void*>(timer));

    return timer;
}

typedef vector<Timer *>::iterator TIterator;
void waitTimer(vector<Timer *>& timer)
{
    for (TIterator tItr = timer.begin(); tItr != timer.end(); ++tItr)
    {
        // Wait for thread
        pthread_join((*tItr)->first, NULL);

        // Clear memory
        delete *tItr;
        *tItr = NULL;
    }
}

class TimerLib
{
    string name;
    vector<Timer *> timers;
    static map<int, TimerLib *> this_map;

public:
    TimerLib(string s)
        : name(s)
    {}

    void start(int sec)
    {
        Timer* timer = setTimer(sec, timerHandler);

        // Store this pointer to map
        this_map[timer->first] = this;

        timers.push_back(timer);
    }

    static void* timerHandler(void* p)
    {
        Timer* timer = static_cast<Timer *>(p);

        // Get this pointer by map
        TimerLib* self = this_map[timer->first];

        sleep(timer->second);

        cout << "Thread id: " << timer->first
            << ", time: " << timer->second
            << ", Name: " << self->name << endl;

        return NULL;
    }

    void wait()
    {
        waitTimer(timers);
    }
};

// A static member variable should be declared
// globally again
map<int, TimerLib*> TimerLib::this_map;

int main()
{
    TimerLib c1("AAA");
    TimerLib c2("BBB");

    // Start timer
    c1.start(10);
    c2.start(5);

    // Wait timer
    c1.wait();
    c2.wait();

	return 0;
}

// Compile: clang++ -pthread
//          -o 04_C_testTimerForId 04_C_testTimerForId.cpp
Code 4. Callback with map for an id and an instance
Thread id: 139971167282944, time: 5, Name: BBB
Thread id: 139971175675648, time: 10, Name: AAA

Start() sets a timer and stores thread id and this pointer in a map container. After that, when timerHandler() is called, it finds this pointer of the target instance and does something with the pointer. Therefore, this is not necessary to be sent a callback function, if it is stored in a static container.

Library with a callback not having this argument

Sometimes, a callback function has conditional behaviors. Code 5 is the example for that case.

// 05_C_testCondition.cpp
#include <iostream>
#include <vector>

#include <unistd.h>
#include <pthread.h>

using namespace std;

typedef pair<pthread_t, int> Timer;

Timer* setTimer(int _time, void* (*func)(void *))
{
    Timer* timer = new Timer();
    timer->second = _time;

    // Create thread
    pthread_create(&(timer->first), NULL, func, static_cast<void*>(timer));

    return timer;
}

typedef vector<Timer *>::iterator TIterator;
void waitTimer(vector<Timer *>& timer)
{
    for (TIterator tItr = timer.begin(); tItr != timer.end(); ++tItr)
    {
        // Wait for thread
        pthread_join((*tItr)->first, NULL);

        // Clear memory
        delete *tItr;
        *tItr = NULL;
    }
}

void* foo(void* p)
{
    Timer* timer = static_cast<Timer*>(p);
    int time = timer->second;

    sleep(time);

    // Print message
	switch (time)
	{
	case 10:
		cout << "Interval 10" << endl;
		break;
	case 5:
		cout << "Interval 5" << endl;
		break;
    default:
        cout << "Wrong time interval" << endl;
	}

	return NULL;
}

int main()
{
	vector<Timer*> timers;
    timers.push_back(setTimer(10, foo));
    timers.push_back(setTimer(5, foo));

	waitTimer(timers);

	return 0;
}
// Compile: clang++ -pthread
//          -o 05_C_testCondition 05_C_testCondition.cpp
Code 5. Callback function with condition
Interval 5
Interval 10

In this example, according to a time interval, print messages are different. If the behaviors are different according to the class type, not only time interval, how could we do that?

To do that, function overriding is useful. The functions for behaviors are redefined in user class. Code 6 shows base and user library for that case and how to use it.

// 06_C_testConditionOverride.cpp
#include <iostream>
#include <vector>
#include <map>

#include <unistd.h>
#include <pthread.h>

using namespace std;

typedef pair<pthread_t, int> Timer;

Timer* setTimer(int _time, void* (*func)(void *))
{
    Timer* timer = new Timer();
    timer->second = _time;

    // Create thread
    pthread_create(&(timer->first), NULL, func, static_cast<void*>(timer));

    return timer;
}

typedef vector<Timer *>::iterator TIterator;
void waitTimer(vector<Timer *>& timer)
{
    for (TIterator tItr = timer.begin(); tItr != timer.end(); ++tItr)
    {
        // Wait for thread
        pthread_join((*tItr)->first, NULL);

        // Clear memory
        delete *tItr;
        *tItr = NULL;
    }
}

// Library
class TimerLib
{
    vector<Timer *> timers;
    // Map for this pointer
	static map<int, TimerLib*> this_map;

public:
	void start(int sec)
	{
        Timer* timer = setTimer(sec, foo);

        // Store this pointer to map
        this_map[timer->first] = this;

        timers.push_back(timer);
	}

	static void* foo(void* p)
    {
        Timer* timer = static_cast<Timer*>(p);

        // Get this pointer from map
        pthread_t handle = timer->first;
        int time = timer->second;
        TimerLib* self = this_map[handle];

        sleep(time);

        // Call print function
        switch (time)
        {
        case 10:
            self->waitSec10();
            break;
        case 5:
            self->waitSec5();
            break;
        default:
            self->wrongSec();
        }

        return NULL;
    }

	void wait()
    {
        waitTimer(timers);
    }

	virtual void waitSec10() {}
	virtual void waitSec5() {}
	virtual void wrongSec() {}
};

// User's Class
class MyTimeLib : public TimerLib
{
public:
    // Print function
	virtual void waitSec10()
	{
		cout << "Interval 10" << endl;
	}

	virtual void waitSec5()
	{
		cout << "Interval 5" << endl;
	}

	virtual void wrongSec()
    {
        cout << "Wrong time interval" << endl;
    }
};

map<int, TimerLib*> TimerLib::this_map;

int main()
{
	MyTimeLib t;

    // Start timer
	t.start(10);

    // Wait for timer
	t.wait();

	return 0;
}
// Compile: clang++ -pthread
//          -o 06_C_testConditionOverride 06_C_testConditionOverride.cpp
Code 6. Library for callback with condition
Interval 10

Now, a user does not need to know how TimerLib class is implemented, but he/she can makes a behavior function in a user class, and execute it. Foo() is a static member function to be called by pthread_create(). handle is a kind of id, and it is used to find the instance pointer, this.

Summary

  • If a callback function has an argument for this pointer, use it.
pthread_create(&tid, NULL, _threadLoop, this);
  • If a callback function does not have an argument for this pointer, use map container or any containers.
static map this_map;

// Register
id = setTimer(ms, timerHandler);
this_map[id] = this;

// Execute
TimerLib* self  = this_map[id];
cout << self->name << endl;
foo();
  • Capsulating a C API is useful to change or extend functionality.

COMMENTS

Name

0 weights,1,abstract class,1,active function,3,adam,2,Adapter,1,affine,2,argmax,1,back propagation,3,binary classification,3,blog,2,Bucket list,1,C++,11,Casting,1,cee,1,checkButton,1,cnn,3,col2im,1,columnspan,1,comboBox,1,concrete class,1,convolution,2,cost function,6,data preprocessing,2,data set,1,deep learning,31,Design Pattern,12,DIP,1,django,1,dnn,2,Don't Repeat Your code,1,drop out,2,ensemble,2,epoch,2,favicon,1,fcn,1,frame,1,gradient descent,5,gru,1,he,1,identify function,1,im2col,1,initialization,1,Lab,9,learning rate,2,LifeLog,1,linear regression,6,logistic function,1,logistic regression,3,logit,3,LSP,1,lstm,1,machine learning,31,matplotlib,1,menu,1,message box,1,mnist,3,mse,1,multinomial classification,3,mutli layer neural network,1,Non Virtual Interface,1,normalization,2,Note,21,numpy,4,one-hot encoding,3,OOP Principles,2,Open Close Principle,1,optimization,1,overfitting,1,padding,2,partial derivative,2,pooling,2,Prototype,1,pure virtual function,1,queue runner,1,radioButton,1,RBM,1,regularization,1,relu,2,reshape,1,restricted boltzmann machine,1,rnn,2,scrolledText,1,sigmoid,2,sigmoid function,1,single layer neural network,1,softmax,6,softmax classification,3,softmax cross entropy with logits,1,softmax function,2,softmax regression,3,softmax-with-loss,2,spinBox,1,SRP,1,standardization,1,sticky,1,stride,1,tab,1,Template Method,1,TensorFlow,31,testing data,1,this,2,tkinter,5,tooltip,1,Toplevel,1,training data,1,vanishing gradient,1,Virtual Copy Constructor,1,Virtual Destructor,1,Virtual Function,1,weight decay,1,xavier,2,xor,3,
ltr
item
Universe In Computer: 02. Sending This Pointer
02. Sending This Pointer
How to use this pointer in class
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXvUavVsX4rYm8cgKQ8rzps7pHmmEVtkIb66G2o5KZFCfjvO96SCEUdaw_DMYzSbdVrB8XvnaKN8ljEE7EBjutI2XvsBL-2BLdijjJRIpAOEpvlhOW-hfWP3ir3wbE488AwdFEu7WKbLgO/s0/
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXvUavVsX4rYm8cgKQ8rzps7pHmmEVtkIb66G2o5KZFCfjvO96SCEUdaw_DMYzSbdVrB8XvnaKN8ljEE7EBjutI2XvsBL-2BLdijjJRIpAOEpvlhOW-hfWP3ir3wbE488AwdFEu7WKbLgO/s72-c/
Universe In Computer
https://kunicom.blogspot.com/2017/09/02-sending-this-pointer.html
https://kunicom.blogspot.com/
https://kunicom.blogspot.com/
https://kunicom.blogspot.com/2017/09/02-sending-this-pointer.html
true
2543631451419919204
UTF-8
Loaded All Posts Not found any posts VIEW ALL Readmore Reply Cancel reply Delete By Home PAGES POSTS View All RECOMMENDED FOR YOU LABEL ARCHIVE SEARCH ALL POSTS Not found any post match with your request Back Home Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sun Mon Tue Wed Thu Fri Sat January February March April May June July August September October November December Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec just now 1 minute ago $$1$$ minutes ago 1 hour ago $$1$$ hours ago Yesterday $$1$$ days ago $$1$$ weeks ago more than 5 weeks ago Followers Follow THIS CONTENT IS PREMIUM Please share to unlock Copy All Code Select All Code All codes were copied to your clipboard Can not copy the codes / texts, please press [CTRL]+[C] (or CMD+C with Mac) to copy