0

For instance

class Foo
{
    void assingTask()
    {
        pthread_t myThread;
        int i;

        pthread_create(myThread, NULL, task, (void*) i)

    }

    void * task(void *val)
    {
        //DO Stuff
    }
};

I keep on getting the error that 'task' isn't a static function. Everything I have seen online mentions that there is a find this. The solutions to the problems are way beyond my skill level. Thank you for the help.

yano
  • 4,827
  • 2
  • 23
  • 35
Nate
  • 17
  • 3
  • 1
    if you're using c++11 or later, consider using [`std::thread`](https://en.cppreference.com/w/cpp/thread/thread) instead. – yano Apr 25 '20 at 23:58
  • @yano I have to use c++98 – Nate Apr 26 '20 at 00:01
  • 2
    Well, you have to read and understand what the issue is, until its no longer "beyond your skill level". There are, unfortunately, no shortcuts to methodical learning, and rigorous study of the most complicated general purpose programming language in use today. You need to thoroughly understand why you cannot have `pthread_create` simply call "task", as is. Once you do, then the solution will be obvious. This is something that simply cannot be explained in one or two short paragraphs on stackoverflow.com, so you'll need a good C++ textbook for this (pun intended). – Sam Varshavchik Apr 26 '20 at 00:01
  • @SamVarshavchik Do you have suggestions on what I can read for this problem then? I am more than willing to learn. I tried referencing my C++ How to Program tenth edition, however, how to thread was not covered in it. – Nate Apr 26 '20 at 00:03
  • 1
    Stackoverflow's [canonical list of C++ books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list), should have some older titles that cover pre-C++11 material, and how to use threads with classes is something that I would expect to be covered in every one of those older textbooks. – Sam Varshavchik Apr 26 '20 at 00:06
  • 1
    I can commiserate. My first thought to get around this would be to make `task` static like it wants, then pass in the address to the object you want to operate on (probably `this`) as an argument, cast back to your class type, now you have an object of your class to do what you want with. – yano Apr 26 '20 at 00:06

2 Answers2

1

The problem is that pthread_create is a C function, not a C++ one, so using it from C++ can be tricky. The third argument needs to be a function pointer, but you're trying to call it with a method pointer which is not the same thing.

C++ does allow implicitly converting a static method pointer into a function pointer, so you can do what you want with that (that's why you get an error saying 'task' isn't static -- because if it was, it could be converted to a function pointer and used). Usually you then use the 4th argument to hold "this" so you can then call a non-static method from the static method

class Foo
{
    void assingTask()
    {
        pthread_t myThread;
        int i;

        pthread_create(&myThread, NULL, start_task, this)

    }
    static void *start_task(void *this_) {
        return static_cast<Foo *>(this_)->task();
    }

    void * task()
    {
        //DO Stuff
    }
};

The above code has the problem that you "lose" the pthread_t handle (don't store it anywhere accessable), so you can't join or detach from the thread, but that could be fixed many ways.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
1

Sure it is possible. Put your data in a structure and wrap it in a trampoline function to jump to your class function:

#include <pthread.h>
#include <stdint.h>

class Foo;

// the context passed to trapoline function
struct FooTaskTrampolineCtx {
    Foo *obj;
    void *val;
};

extern "C" void *FooTaskTrampoline(void *ptr);

struct Foo {
    void assingTask() {
        pthread_t myThread;
        int i;
        // note - memory allocated dynamically
        struct FooTaskTrampolineCtx *c = new FooTaskTrampolineCtx;
        c->obj = this;
        c->val = (void*)(uintptr_t)i;
        pthread_create(&myThread, NULL, FooTaskTrampoline, c);
    }

    void * task(void *val) {
        //DO Stuff
    }
};

extern "C" void FooTaskTrampolineCleanup(void *ptr) {
    struct FooTaskTrampolineCtx *c = (struct FooTaskTrampolineCtx *)ptr;
    delete c;
}

// trampolines to task method
extern "C" void *FooTaskTrampoline(void *ptr) {
    struct FooTaskTrampolineCtx *c = (struct FooTaskTrampolineCtx *)ptr;
    void *ret = NULL;
    // remember to pick out the trash the PThread(TM) way
    pthread_cleanup_push(FooTaskTrampolineCleanup, ptr);
    ret = c->obj->task(c->val);
    pthread_cleanup_pop(1);
    return ret;
}
KamilCuk
  • 120,984
  • 8
  • 59
  • 111