0

I'm from Colombia so the error is in Spanish. This seems the fastest place to get an answer...

I've been trying to make a simple program that creates threads and saves the information in a vector but when I build the code the next error appears:

...Lanzador.cpp|19|error: no se puede convertir ‘void* (Hilo::*)(void*)’ a ‘void* (*)(void*)’ para el argumento ‘3’ para ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)’|

I have three files: the header for Hilos that says:

    #ifndef HILO_H
    #define HILO_H
    using namespace std;

    class Hilo
    {
        public:
            Hilo();
            virtual ~Hilo();
            void addHilo(int);
            void* ImprimirHilo(void*);

        protected:
        private:
        };

    #endif // HILO_H

Hilo.cpp that says:

    #include <iostream>
    #include <vector>
    #include <cstdlib>
    #include <pthread.h>
    #include <unistd.h>
    #include "Hilo.h"
    using namespace std;
    vector<int> info (1);
    Hilo::Hilo()
    {
    //ctor
    }

    Hilo::~Hilo()
    {
     //dtor
    }

    void Hilo::addHilo(int tiempo){

         info.push_back(tiempo);

    }


    void* Hilo::ImprimirHilo(void *threadid)
    {
         long tid;
         tid = (long) threadid;
        int n =info.at(tid);
        for (int i=n; i>0; i-- ){
        info.at(tid)=i;
        cout << "El hilo numero: " << tid << " tiene " << i <<" segundos"<< endl;
        sleep(1);
        }
        pthread_exit(NULL);
      }

And the class that has the main Lanzador.cpp

    #include <iostream>
    #include <cstdlib>
    #include <pthread.h>
    #include "Hilo.h"
    using namespace std;
    int main (){
        Hilo h;
        pthread_t threads;
        int tiempo=0;
        int rc;
        int contador=0;
        cout << "Para salir oprima 0 \n"<<endl;
        cout << "Escriba el tiempo del hilo" << endl;
        while (true){
            cin >> tiempo;
            if (tiempo>0){
                contador++;
                h.addHilo(tiempo);
                rc = pthread_create(&threads, NULL,&h.ImprimirHilo, (void*)contador);
                if (rc){
                     cout << "Error:unable to create thread," << rc << endl;
                     exit(-1);
                }
           }
      }


      pthread_exit(NULL);

   }

I hope that you people can help me. Sorry for the bad English and thanks for the help

Meredith
  • 3,928
  • 4
  • 33
  • 58
user2782149
  • 39
  • 2
  • 9
  • 4
    Non-static member functions are not functions. You cannot *call* a member function (it needs an object!). There are thousands of duplicates of this question. – Kerrek SB Sep 15 '13 at 22:34
  • 1
    And start from here: http://stackoverflow.com/questions/1151582/pthread-function-from-a-class – Nemanja Boric Sep 15 '13 at 22:35
  • 1
    You can probably change your locale to English for the GCC / Make run somehow. – millimoose Sep 15 '13 at 22:35
  • 1
    @millimoose, yep, just set LANG=C – Jonathan Wakely Sep 15 '13 at 23:07
  • Lateral suggestion: wouldn't the new `` stuff work better than trying to combine pthreads and C++? Or Boost.Thread if `` isn't available. (That said I'll admit all I know about those libraries is that they exist.) – millimoose Sep 16 '13 at 11:12

2 Answers2

1

Based on the signatures mentioned in the error message you are trying to use a member function where a void() function or pointer thereof is needed: using a member function directly won't work! You need to realize that a member function apparently taking no argument actually does have a hidden argument: the this pointer! Thus, an object needs to be provided. Since you use pthread_create() there isn't any way around that: you need to come up with a normal function taking no arguments. Since the function probably needs to be declared extern "C" you can't use a static member function either.

Something doesn't seem right, however, as pthread_create() actually takes a void*(*)(void*) as argument, not a void*(*)(void) as is claimed in the error message: the void* can be used to pass information to the thread entry function, e.g., a pointer to an object which could be restored to the correct type before calling a suitable member function.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
0

You cannot use non static methods in threading. You will have to use the following pattern to get an instance aware method multi-threaded.

baseclass.h

class baseclass
{
    int a;
    static void __stdcall threaded(void* params);
}

baseclass.cpp

void __stdcall 
threaded(void* params)
{
    // this is your class instance
    pThis = static_cast<baseclass*>(params);
    printf("%d", pThis->a);
}

main.cpp

// class instance is entered as the parameter
rc = pthread_create(&threads, NULL, Hilo::ImprimirHilo, (void*)&h);
Serdalis
  • 10,296
  • 2
  • 38
  • 58
  • `__stdcall` is not part of the C++ standard while `extern "C"` is (which, however, means that the function can't be a `static` member). Also, the correct cast to restore a pointer to `void*` obtained by an implicit conversion to the original object pointer type where it came from by an implicit conversion is `static_cast(params)`. – Dietmar Kühl Sep 15 '13 at 22:42
  • @DietmarKühl Interesting! I've always been using `reinterpret_cast` Thanks for the correction. You are correct about `__stdcall` I thought it was able to be used in GCC too though? – Serdalis Sep 15 '13 at 22:44
  • I prefer standard facilities over compiler extensions which won't work when compiling with the next compiler. What's the point of being locked into a specific compiler if the same logic can be implemented in portable portable manner at no or very little cost. – Dietmar Kühl Sep 15 '13 at 22:46
  • @DietmarKühl I have only ever worked in MSVC / GCC environments. If an extension is available in both, makes the code more readable and makes my life easier then it is detrimental to not use it. I understand your view but using `extern "C"` to do this seems a bit hacky to me. A question of style / portability mostly. – Serdalis Sep 15 '13 at 22:49