I'm using Xcode and C++ to make a simple game.
The problem is the following code:
#include <pthread.h>
void *draw(void *pt) {
// ...
}
void *input(void *pt) {
// ....
}
void Game::create_threads(void) {
pthread_t draw_t, input_t;
pthread_create(&draw_t, NULL, &Game::draw, NULL); // Error
pthread_create(&input_t, NULL, &Game::draw, NULL); // Error
// ...
}
But Xcode gives me the error: "No matching function call to 'pthread_create'". I haven't an idea 'cause of I've included pthread.h already.
What's wrong?
Thanks!
As Ken states, the function passed as the thread callback must be a (void*)(*)(void*) type function.
You can still include this function as a class function, but it must be declared static. You'll need a different one for each thread type (e.g. draw), potentially.
For example:
class Game {
protected:
void draw(void);
static void* game_draw_thread_callback(void*);
};
// and in your .cpp file...
void Game::create_threads(void) {
// pass the Game instance as the thread callback's user data
pthread_create(&draw_t, NULL, Game::game_draw_thread_callback, this);
}
static void* Game::game_draw_thread_callback(void *game_ptr) {
// I'm a C programmer, sorry for the C cast.
Game * game = (Game*)game_ptr;
// run the method that does the actual drawing,
// but now, you're in a thread!
game->draw();
}
compilation of threads using pthread is done by providing options -pthread.
Such as compiling abc.cpp would require you to compile like g++ -pthread abc.cpp else would
give you an error like undefined reference topthread_create collect2: ld returned 1 exit status` . There must be some similar way to provide pthread option.
You're passing a member function pointer (i.e. &Game::draw) where a pure function pointer is required. You need to make the function a class static function.
Edited to add: if you need to invoke member functions (which is likely) you need to make a class static function which interprets its parameter as a Game* and then invoke member functions on that. Then, pass this as the last parameter of pthread_create().
Related
I have a problem in which a function call during executing is calling a completely wrong implemented interface function that is overloaded. I call a function passing a bool parameter and the implemeted function actually being called is the one with a float paramater...
Here's my use case, may be a little bit confusing:
I'm writing a game in which a user will write arduino code in a Unreal Engine (UE) widget that will be saved into a .cpp file.
Behind the curtains, usercode.cpp (saved file) will get the user written code and "inject" some useful stuff, making a small code look like this:
#include "IArduino.h"
extern "C"
{
__declspec(dllexport) void setup();
__declspec(dllexport) void loop();
__declspec(dllexport) void InitArduinoPtrs(IArduino*);
};
IArduino* arduinoPtr = nullptr;
void InitArduinoPtrs(IArduino* InArduinoPtr)
{
arduinoPtr = InArduinoPtr;
}
void setup()
{
arduinoPtr->pinMode(true);
}
**Injected code: "IArduino.h", "extern C stuff", "arduinoPtr" and "InitArduinoPtrs()"
I have a interface called "IArduino" that has a function defined as virtual that is overloaded (test only):
class IArduino
{
public:
virtual void pinMode(float) = 0;
virtual void pinMode(bool) = 0;
};
I'm compiling this usercode.cpp as a shared library (usercode.cpp using IArduino.h):
g++ -c -I[IArduino.h_PATH] -Wall -fpic ./usercode.cpp -o ./usercode.o 2>&1
g++ -shared -o ./usercode.so ./usercode.o 2>&1
On my Unreal Engine project, I created a "ArduinoImpl[.h,.cpp]" that implements "IArduino" interface:
class ARDUCOMPILATIONTEST_API ArduinoImpl : public IArduino
{
public:
void pinMode(bool portNumBoolTest);
void pinMode(float portNumTest);
};
At runtime in Unreal Engine, I'm using GetProcAddress() to get setup() and InitArduinoPtrs() functions.
With linked InitArduinoPtrs(), I call it passing the pointer to a new object of "ArduinoImpl()" (that implements IArduino.h):
At another class that runs in runtime:
m_setup_function = (m_setup)FPlatformProcess::GetDllExport(m_dllHandle, TEXT("setup"));
m_init_function = (m_init)FPlatformProcess::GetDllExport(m_dllHandle, TEXT("InitArduinoPtrs"));
ArduinoImpl* arduinoImplPtr = new ArduinoImpl();
if (m_init_function)
m_init_function(arduinoImplPtr);
if (m_setup_function)
m_setup_function();
My problem is, usercode.cpp setup() is run, then:
When the "arduinoPtr->pinMode(true)" is called, it's calling "ArduinoImpl::pinMode(float)" instead of "ArduinoImpl::pinMode(bool)", completely messing up the overloaded call. Moreover, if I try to write "arduinoPtr->pinMode(2.5f)", it calls the bool overload instead of float overload... The same thing happens if I try with different parameters, such as int, string, etc.
Does anybody know why this is happening?
I tried logging the results, such as logging the float I receive when "arduinoPtr->pinMode(true)" is called and I get garbage value (such as 0.5, 512.803, 524288.187500, ...). Trying to log the "bool" value when "arduinoPtr->pinMode(2.5f)" is called, I get "208".
I tried forcing a cast on call like "arduinoPtr->pinMode(static_cast(true))" and it still calls the float param overloaded function.
I tried with different params type and the same thing keeps hapenning.
I am trying to link to an external library in my QT application. The external library has a header file with the following relevant code I'm trying to call:
extern VGRABDEVICE_API bool V_AssignFrameSizeCallback(IGrabChannel* pChannel, void* pFunc);
In the demo C++ program provided, which has no problems compiling, the following relevant code is:
// in main.cpp
void _stdcall MyFrameSizeCallback(T x) {
do_stuff;
}
int main(int argc, char* argv[]) {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, MyFrameSizeCallback);
}
I am trying to incorporate this code into my QT application, but getting problems. In my mainwindow.cpp file:
void _stdcall MainWindow::MyFrameSizeCallback(T x) {
do_stuff;
}
void MainWindow::someFunction() {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, &MainWindow::MyFrameSizeCallback);
}
The error I'm getting is:
error: C2664: 'bool V_AssignFrameSizeCallback(IGrabChannel *,void *)' :
cannot convert argument 2 from 'void (__cdecl MainWindow::* )(T)' to 'void *'
There is no context in which this conversion is possible
What do I need to do? Thanks.
You have two problems. First, void* is a data pointer, not a function pointer. According to the C++ standard, casting between the two is not expected to work. Some platforms provide a stronger guarantee... for example Windows GetProcAddress and *nix dlsym mix the two.
Next, your &MainWindow::MyFrameSizeCallback is not a function pointer, it is a pointer-to-member-function. Calling it requires a MainWindow object, which the external library doesn't know anything about.
You need to provide an ordinary function, not a member function, to the library. If you have some way to get ahold of the MainWindow* object pointer, you can then call its member function to do the real work. Sometimes the library provides a "context" parameter which is passed to your callback; that's a great place to put the object pointer. Otherwise, you'll need to store your MainWindow* in a global variable. Easy if you have just one, while if you have more than one you might go with std::map<IGrabChannel*, MainWindow*>.
Code:
MainWindow* MainWindow::the_window;
void MainWindow::MyFrameSizeCallback(T x)
{
do_stuff;
}
void _stdcall MyFrameSizeCallbackShim(T x)
{
MainWindow::the_window->MyFrameSizeCallback(x);
}
void MainWindow::someFunction()
{
IGrabChannel* pChannel0 = something;
the_window = this;
V_AssignFrameSizeCallback(pChannel0, &MyFrameSizeCallbackShim);
}
If the parameter x isn't an IGrabChannel, change the map datatype and insertion logic accordingly. If the parameter x isn't some sort of unique predictable identifier, you may be limited to only doing callbacks to one MainWindow instance.
I'm developing a simple instant-messaging software on Ubuntu 12.10, it's client requires GUI.
In the main window of the client, i need to create a thread to keep listening messages received from the server.
Here is the error message:
main.cpp:-1: In function 'int main(int, char**)':
main.cpp:27: error: invalid conversion from 'void*' to 'void* (*)(void*)' [-fpermissive]
/usr/include/pthread.h:225: error: initializing argument 3 of 'int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)' [-fpermissive]
In the maininterface.h:
Class MainInterface: public QWidget
{
public:
explicit MainInterface(QWidget *parent = 0);
~MainInterface();
void* ServerMSGWatch(void *threadArgs=NULL); // function run in the new thread
};
It's definition in maininterface.cpp is:
void* MainInterface::ServerMSGWatch(void *threadArgs)
{
pthread_detach(pthread_self());
char arrServerMSGRecv[SERVER_MSG_MAX_SIZE + 1];
while(1){
recv(Login::sockClnt, arrServerMSGRecv, SERVER_MSG_MAX_SIZE+1, 0);
Handle_Server_MSG(arrServerMSGRecv);
memset(arrServerMSGRecv, 0, SERVER_MSG_MAX_SIZE+1);
}
return NULL;
}
in main.cpp:
MainInterface mWindow;
mWindow.show();
pthread_t pthreadID;
pthread_create(&pthreadID, NULL, mWindow.ServerMSGWatch(), NULL);
and in this question, i figured out that maybe there's something wrong with using a C++ compiler to compile c code.
so i tried to add a 'c_pthread.h':
#ifndef C_PTHREAD_H
#define C_PTHREAD_H
#ifdef __cplusplus
extern "C" {
#endif
void* ServerMSGWatch(void *threadArgs=NULL);
void Handle_Server_MSG(char *arrServerMSGRecv);
#ifdef __cplusplus
}
#endif
#endif // C_PTHREAD_H
and c_pthread.cpp:
void* ServerMSGWatch(void *threadArgs=NULL)
{
//definition
}
void Handle_Server_MSG(char *arrServerMSGRecv)
{
//definition
}
then invoke it in main.cpp:
#include "c_pthread.h"
pthread_t pthreadID;
pthread_create(&pthreadID, NULL, ServerMSGWatch(), NULL);
but i still got the same error.
PS: sorry about some malapropisms.
You have two problems: The first is that you call the function instead of passing it. The other is more subtle, and is that you can't use a non-static class member function as a thread function.
The reason for the last problem is because non-static member function have a hidden first argument that is the this pointer.
In this case you can solve it by adding a static member function, and pass a pointer to the object as argument to the thread function. Then the static function calls the actual function in the object:
class MainInterface: public QWidget
{
public:
...
static void* StaticServerMSGWatch(void* arg)
{
reinterpret_cast<MainInterface*>(arg)->ServerMSGWatch();
return nullptr;
}
void ServerMSGWatch(); // function run in the new thread
};
...
pthread_create(&pthreadID, NULL, &MainInterface::StaticServerMSGWatch, &mWindow);
If you have a C++11 capable compiler and library, you could use std::thread instead:
std::thread myThread(&MainInterface::ServerMSGWatch, &mWindow);
As you see, you no longer need the static member function.
You're using Qt, so I strongly suggest using QThread. This will guarantee compatibility and the interop with the rest of your program will be better.
That being said, you need to pass a function pointer to pthread_create, and a member function pointer is not a function pointer: either make it static or make it a freestanding function.
In C++11, there's no need to muck around with low-level system libraries:
std::thread thread([&]{mWindow.ServerMSGWatch();});
If you're stuck with a historic version of C++ then, since you say you're using Qt, you might consider its thread class QThread.
If you're stuck with pthreads then, being a C API, it knows nothing about member functions, so you'll need a non-member, or static member function. (Strictly speaking, you should only use a non-member function declared extern "C", but in practice C++ functions will work on any sensible implementation).
So you'll need a wrapper function to call the member function:
void * CallServerMSGWatch(void * p) {
return static_cast<MainInterface*>(p)->ServerMSGWatch();
}
and tell pthread_create to pass a suitable pointer through to this:
pthread_create(&pthreadID, NULL, CallServerMSGWatch, &mWindow);
mWindow.ServerMSGWatch() is a function call.
mWindow.ServerMSGWatch is a function pointer.
I'm having issues with multithreading and multifile projects. Works fine when testing with a single file project but as I am trying to keep my headers separated from my implimentation, is there a way to make this work?
the error I am getting is:
error C3867: 'class1::Update': function call missing argument list; use '&class1::Update' to create a pointer to member
Sadly, the suggestion there doesn't work. Any help would be greatly appreciated.
Class1.H
class class1
{
public:
class1();
~class1();
private:
thread sThread;
void Update();
};
Class1.cpp
int class1::Initialize()
{
this->sThread = std::thread(Update);
}
As you say, the error is:
'class1::Update': function call missing argument list; use '&class1::Update' to create a pointer to member
So do that. Once you do you will find that you then need to use std::bind() to attach an instance of the class to the member function. That will look like:
thread(bind(&class1::Update, this))
So, I'm trying to compile my code, but the compiler keeps complaining that "'mysnake' undeclared (first use this function)", but I declared it.
This is my Main.cpp, wehre it is declared.
#include "Class.h"
#include "Snake.h"
int main(int argc, char* args[]){
Prog run;
if((run.Init())==false){
return(1);
}
Snake mysnake;
if(run.LoadFiles()==false){
return(1);
}
run.MainLoop();
if(run.Draw()==false){
return(1);
}
run.CleanUp();
return(0);
}
And this is the file that makes the compiler complain (AFAIK it's the first file with any reference to 'mysnake' that gets compiled)
#include "Class.h"
#include<sstream>
#include "Snake.h"
bool Prog::Draw(){
std::stringstream message;
SDL_Rect position;
SDL_BlitSurface(image, NULL, screen, NULL);
int s=mysnake.EndSnake();
message<<"Your snake was "<<s<<" blocks long.";
msg=TTF_RenderText_Solid(font, message.str().c_str(), font_color);
if(msg==NULL){
return(false);
}
position.x=(WWIDTH-msg->w)/2;
position.y=(WHEIGHT-msg->h)/2;
SDL_BlitSurface(msg, NULL, screen, &position);
SDL_Flip(screen);
return(true);
}
I have thought about it for over an hour and I still can't understand why it does this. By the way I'm using Bloodshed Dev C++
I'd be very grateful for help.
Inside your Draw function there is no variable declared called mysnake. That function can't see the mysnake that's declared in main because it is local to main. You need to pass your mysnake object to the Draw function so that it knows which snake you're actually talking about.
To do that, give Draw an argument of type const Snake&, a "reference to const Snake" (or take away the const if EndSnake is a non-const member function):
bool Prog::Draw(const Snake& snake) {
// ...
}
And when you call Draw in main, do this:
run.draw(mysnake);
Now your Draw function has a variable called snake which was passed in from main. Because the argument is a reference, the Snake object that it sees is exactly the same object as in main. If the argument had been of type Snake instead of const Snake&, then you would get a copy of the mysnake from main.
Some extra advice:
We usually write conditions like (run.Init())==false as just !run.init() - it reads much better. Returning is also usually written as return true;, rather than return(true);, but that's up to you.
The fact that mysnake is declared in main does not allow one to use it in Prog. You probably want to transmit a reference to mysnake to the Draw method.
Through the constructor or through the call to the method.
Prog run(mysnake);
run.draw();
or
run.draw(mysnake);