C++: Warning (Anachronism) in Solaris Studio when

2019-07-19 03:04发布

I've been facing this warning.

I have a main C++ program which creates several threads. These threads run a function which is in a specific class. In order to do that, this class has a static function which returns the real function I am using to run in these threads. I'll paste the relevant parts of my code for you to understand it better.

These are the relevant parts of Car.h, the headers of the class whose function is run in the thread:

[...]
class Car {

public:
    [...]
    void *GoForward(void);                 //Runs in the thread
    static void* GoForward_helper(void *); //Sends the previous one to the thread
    [...]

This is the function in Car.cpp passed to pthread_create as argument, which returns the function which really runs in the thread. It is the only way I found to run in a thread a function of a different class:

[...]
void *Car::GoForward_helper(void *context) {

    //Just getting parameters, not big deal
    ThreadParameters* parameters = (ThreadParameters*) context;
    int newSlot = parameters->GetSlot();
    parameters->GetCar()->setSlot(newSlot);

    //Returns the function I want to run in the thread
    return parameters->GetCar()->GoForward();
}
[...]
void* Car::GoForward(void) {
    //Tasks which actually run in the thread
}
[...]

These are the parameters sent to the helper function. Nothing relevant, I paste them for your convenience:

[...]
class ThreadParameters {
public:
    ThreadParameters(Car*, int);
    Car* GetCar();
    int GetSlot();
    [...]
private:
    Car* context;
    int slot;
[...]

...and finally this is the code in main() which creates the thread:

[...]
vector<Car *> cars;    //Pointers to objects whose functions I want to run in threads
int threadsLaunched = 0;
pthread_t threads[numberOfThreads]; 
vector<int> freeSlots; //The number of threads is limited
[...]          
int slot = freeSlots.at(0);
threadCode = pthread_create(&threads[slot], NULL, 
                    &Car::GoForward_helper, 
                    new ThreadParameters(cars.at(threadsLaunched), slot));

I am programming it in Solaris 10, using Oracle Solaris Studio 12.3. When building the project, I get this warning corresponding to the line in main() where I create the threads:

"main.cpp", line 80: Warning (Anachronism): Formal argument 3 of type extern "C" void*()(void) in call to pthread_create(unsigned*, const _pthread_attr*, extern "C" void*()(void), void*) is being passed void*()(void).

The code works like a charm, but I still get this warning when compiling and, honestly, I hate not having a fully clean compiling process. I have found dozens of solutions using extern "C", but none of these solutions match with the structure of my code, so none of them worked for me, and I would like to get rid of any warning (solving them, not hiding them).

1条回答
Viruses.
2楼-- · 2019-07-19 03:24

You're getting the warning because pthread_create() expects a pointer to function with C language linkage, but you're passing it Car::GoForward_helper which has C++ language linkage. While in practice this will most likely work, these two are actually different; for example, C and C++ linkage functions could be using different calling conventions.

Unfortuantely, a class member (even a static one) cannot have language linkage other than C++. In other words, going strictly by the letter of the rules, it's impossible to use a static member function as a callback where a C function is expected.

To solve this, you must make the helper a free function and give it C language linkage:

[...]
class Car {

public:
    [...]
    void *GoForward(void);                 //Runs in the thread
    [...]
};

extern "C" void* GoForward_helper(void *); //Sends GoForward() to the thread

Implemented like this:

extern "C" void *GoForward_helper(void *context) {

    //Just getting parameters, not big deal
    ThreadParameters* parameters = (ThreadParameters*) context;
    int newSlot = parameters->GetSlot();
    parameters->GetCar()->setSlot(newSlot);

    //Returns the function I want to run in the thread
    return parameters->GetCar()->GoForward();
}

An additional option, especially if the function needs member-like access, you could keep the static one and simply delegate to it:

[...]
class Car {

public:
    [...]
    void *GoForward(void);                 //Runs in the thread
    static void* GoForward_helper(void *); //Sends the previous one to the thread
    [...]
};

extern "C" void* GoForward_helper_C(void *);

Implemented like this:

extern "C" void* GoForward_helper_C(void *arg) {
  return Car::GoForward_helper(arg);
}
查看更多
登录 后发表回答