S60 Open C
Threads, Processes, IPC, and Synchronization

Threads, Processes, IPC, and Synchronization

Table of Contents

How to invoke thread entry functions in hybrid applications
Solution 1
Solution 2
Solution 3
Solution 4

 


How to invoke thread entry functions in hybrid applications

Since Open C standard libraries can be used by hybrid applications with standard C, standard C++, and Symbian C++ codes, we can make use of some design patterns for using some of these APIs in such hybrid applications. One such example can be the use of pthread_create within C++ codes with many classes.

A prototype of pthread_create is shown below:

int pthread_create(pthread_t* threadhdl, pthread_attr_t* attrib, thread_begin_routine begin_routine,  void* param);

This function creates a thread, with attributes specified by attrib, within a process. If attrib is NULL, the default attributes will be used. On successful completion, pthread_create() will store the ID of the created thread in the location referenced by threadhdl and will create the thread for which the user-entry point will be begin_routine.

In case of hybrid applications, we can also refer to C++ methods and class members as thread_begin_routine. There are different ways in which we can have a class member function as thread_begin_routine. Let's take a scenario where a user wants to send a member function of a class as the ThreadEntry point:

Assume that the class is as shown below:

class Sample {
    public:
       Sample();
      ~Sample();
      void ThreadEntryFunction(void*);
      ...
      private:
      ...
   };  

If the user tries to create a thread with the following code:

Sample sam;    
pthread_t thrd;    
pthread_attr_t attr;    
pthread_attr_init(&attr);    
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);      
int pId = pthread_create(&thrd, &attr, sam.ThreadEntryFunction, NULL);  // Error Here... 

the code will cause a compilation error as we are referring to a class member as the thread entry function. There are different solutions to handle the resulting compilation error.

 


Solution 1

Change the function to static,

class Sample {
    public:
       Sample();
      ~Sample();
      static void ThreadEntryFunction(void* );
      ...
    private:
      ...
   };  

and use it as follows:

int pId = pthread_create(&thrd, &attr, Sample::ThreadEntryFunction, NULL);   

This solution does not allow us to access non-static members from a static function. So all the members that are referred to by function ThreadEntryFunction should be made static.

 


Solution 2

As we need to make all the class data members accessed within the static member function as static, the alternative will be to add one local function, which will act as the thread entry function and an send object to that function. This function will invoke the actual function as the thread entry function. The code below illustrates this:

void* EntryFunction(void* aPtr) {
   Sample* sam = static_castSample*>(aPtr);
   sam->ThreadEntryFunction();
}

And create the pthread using the following code:

Sample sam;
  ....
  int pId = pthread_create(&thrd, &attr, EntryFunction, &sam);  

 


Solution 3

This solution is a variation of solution 2. We can make use of a template function which takes care of calling a predefined member function of any class. The requirement for this solution is that all the classes (object) that we are sending to the template function should have a thread entry function with the same name.

templatetypename <ClassName> 
void* EntryFunction(void* aPtr) {
   ClassName* sam = static_cast<ClassName*>(aPtr);
   sam->ThreadEntryFunction();
}

The advantage is that the user can use it for any type of class, but we should make sure that there is a function named void ThreadEntryFunction() (with definition) in that class. We can impose this by having an abstract class with pure virtual method for ThreadEntryFunction(), so that all the derived classes will implement this function. The example below assumes that we have two classes:

class Sample {
public:
   Sample(int aVal = 0) : iVal(aVal) { }
   ~Sample() { }
   //Will be used as thread entry function
   void ThreadEntryFunction() {}
private:
   int iVal;
};

class OtherClass {
   public:
   OtherClass(int aVal = 0) : iVal(aVal) { }
   ~OtherClass() { }
   //Will be used as thread entry function
   void ThreadEntryFunction() {}
private:
   int iVal;
};

Notice that both Sample and OtherClass have a function ThreadEntryFunction(). This solution can be used as shown below:

int main() {
   Sample sam;
   OtherClass obj;
   pthread_t thrd;
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

   pthread_create(&thrd, &attr, EntryFunction<Sample>,  &sam);
   pthread_create(&thrd, &attr, EntryFunction<OtherClass>,  &obj);
   pthread_attr_destroy(&attr);
   return 0;
}

 


Solution 4

This is a generic solution that may look a little complex at first, but is efficient to use.

The solution is as shown below:

template<class T, void (T::*EntryFunction)()> 
void* MyThreadEntryFun(void* aPtr) {
   T* p = static_cast<T*>(aPtr);
   (p->*EntryFunction)();
   return 0;
}

This template thread entry function will take an object (pointer) and a function pointer that needs to be called. The signature or prototype of the class member function that will be passed should match the one mentioned in the template.

Let's assume that we have two classes as shown below:

class Sample {
public:
   Sample(int aVal = 0) : iVal(aVal) { }
   ~Sample() { }
   //Will be used as thread entry function
   void ThreadEntryFunctionOne() {}
private:
   int iVal;
};

class OtherClass {
public:
   OtherClass(int aVal = 0) : iVal(aVal) { }
   ~OtherClass() { }
   //Will be used as thread entry function
   void ThreadEntryFunctionTwo() {}
private:
   int iVal;
};

Observe the prototype of those two functions within the class. Notice that they have different names. Now, we can have some codes like the following:

int main() {
   Sample sam;
   OtherClass obj;
   pthread_t thrd;
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

   pthread_create(&thrd, &attr, MyEntryFun<Sample, Sample::ThreadEntryFunctionOne>, &sam);
   pthread_create(&thrd, &attr, MyEntryFun<OtherClass, OtherClass::ThreadEntryFunctionTwo>, &obj);
   pthread_attr_destroy(&attr);
   return 0;
}

The advantage of this solution is that the user can call any function of a class as the thread entry point that has a matching prototype.

Give feedback of this section


©Nokia 2007

Back to top


This material, including documentation and any related computer programs, is protected by copyright controlled by Nokia. All rights are reserved. Copying, including reproducing, storing, adapting or translating, any or all of this material requires the prior written consent of Nokia. This material also contains confidential information, which may not be disclosed to others without the prior written consent of Nokia.

Nokia is a registered trademark of Nokia Corporation. S60 and logo is a trademark of Nokia Corporation. Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. Other company and product names mentioned herein may be trademarks or tradenames of their respective owners.