C++ WinForms parameters through System::Threading::ParameterizedThreadStart - c++

I have to create new thread and send parameters to the threaded function, can't make it work though.
I was working according to this reference: http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx
Here is the thread creation (with the errors in the comments):
System::Threading::Thread^ T = gcnew System::Threading::Thread(gcnew System::Threading::ParameterizedThreadStart(this, &Server::ClientHandler)); // ERROR: 'void Server::ClientHandler(System::Object ^,System::Object ^)' : the specified function does not match the delegate type 'void (System::Object ^)'
T->Start(ClientSocket); // ERROR: 'System::Threading::Thread::Start' : no overloaded function takes 2 arguments
Here is ClientHandler decleration:
void Server::ClientHandler(Object^ data, Object^ data1);
I tried it with only one parameter, and I had only the second error.
P.S, in ClientHandler function I have to convert the Object^ parameters to SOCKET* and SOCKADDR_IN*, how it can be done?
My try:
SOCKET* _Sock = (SOCKET*)data;
SOCKADDR_IN* _ADDR = (SOCKADDR_IN*)data1;
I'm using visual studio 2012.

Pretty sure that declaration for Server::ClientHandler is incorrect.
Should be:
void Server::ClientHandler(Object^ data)
{
//Do stuff with data here..
}
System::Threading::Thread^ T = gcnew System::Threading::Thread(gcnew System::Threading::ParameterizedThreadStart(this, &Server::ClientHandler));
T->Start("Pass Your Data Here");

Related

C++ make::shared wrapping on existing raw pointer

I am working on a small wrapper for an FMOD library. Below is a snippet of the code that I have, and there are other libraries that manage the SoundData class:
class SoundData
{
public:
...
std::string mSoundName;
std::shared_ptr<FMOD::Sound> mFmodSoundHandle;
...
}
void SoundLib::CreateSound(SoundData& data)
{
FMOD::Sound *sound = nullptr;
system->createSound(data.mSoundName.data(), FMOD_DEFAULT, nullptr, &sound);
data.mFmodSoundHandle = std::make_shared<FMOD::Sound>(sound);
}
Trying to compile this snippet of the code, I get this error:
Error C2664 'FMOD::Sound::Sound(const FMOD::Sound &)': cannot convert argument 1 from 'FMOD::Sound *' to 'const FMOD::Sound &' SoundLib ...\MSVC\14.29.30133\include\xutility 158
I cannot quite understand if I am using std::make_shared() in the wrong way here? The goal here is to save the output from createSound() that is passed as a sound variable into the structure SoundData. Variable data will be managed afterwards.
You're passing a pointer where you should pass a reference. Try *sound.
Notice that you're not wrapping a pointer, you're creating a new instance of Sound and copying the value of *sound into it.
To wrap it consider:
data.mFmodSoundHandle.reset(sound);

Trying to pass an instance to a bound function C++

This has got to be something simple, but I'm not experienced with C++ or bound functions. Basically I'm trying to do this:
server.on("/capture", HTTP_GET, std::bind(&SolarCamera::serverCapture, this, server));
The problem is when I use the server instance argument. Other similar binds without that instance are fine.
server is defined here as a protected method.
//SolarServer.hpp
class SolarServer
{
public:
SolarServer(int port);
void startRouter();
protected:
ESP8266WebServer server;
};
//SolarServer.cpp
SolarServer::SolarServer(int port): server(port){}
void SolarServer::startRouter() {
//capture cam
server.on("/capture", HTTP_GET, std::bind(&SolarCamera::serverCapture, this, server));
...
And all I want to do is pass that server instance to the SolarCamera class so I can return a camera stream to that instance. The camera interface is like this
// SolarCamera.hpp
class SolarCamera
{
public:
SolarCamera();
void serverCapture(ESP8S266WebServer& server);
protected:
ArduCAM myCAM;
};
But the compiler balks at the method invocation and dumps a gnarly log:
error: pointer to member t
ype 'void (SolarCamera::)(ESP8266WebServer&)' incompatible with object type 'SolarServer'
error: return-statement wi
th a value, in function returning 'void' [-fpermissive]
In your bind statement you're using this, which points to an instance of SolarServer, but, the method you're trying to bind to is of type SolarCamera. Instead of using this, you need to give it a reference to a SolarCamera instance.

C++ Error on void type parameters

I've got this header:
class jmmvAsync
{
public:
static void run(LPCTSTR msg);
};
and this .cpp
void jmmvAsync::run(LPCTSTR msg){
MessageBox(NULL, msg, NULL, NULL);
}
And I'm calling a this function:
LPTCSTR file = "file";
thread t(jmmvAsync::run(file), 0);
thread function has this structure:
thread::thread(void (*aFunction)(void *), void * aArg)
Why am I getting wrong types when calling to "thread"?
Error code:
COMPILE : error C2664: 'tthread::thread::thread(void (__cdecl *)(void *),void *)' : cannot make conversion of parameter 1 with type 'void' to 'void (__cdecl *)(void *)'
thread function expects paramater 1 to be void (__cdecl *)(void *) and my function is just void. I don't know how to make my function named run the same type as requested.
As it was mentioned in comments (but maybe in an unclear fashion), your code tries to pass the return value of the function, instead of the pointer to the function.
This constructor
thread::thread(void (*aFunction)(void *), void * aArg)
expects a pointer to a function as the first argument.
This
jmmvAsync::run(file)
invokes the function and its result is the function's return value (which is void). This is absolutely not what you want. You want an address of the function:
&jmmvAsync::run
Send it to your constructor this way:
LPTCSTR file = "file";
thread t(&jmmvAsync::run, file);
Note: the second parameter is the file, not 0. This is a common pattern in C: you pass the address of the function and its parameter, which is of type void*, and the library code promises to call that function later, passing the parameter to it.
BTW as Aaron McDaid mentions, the type of jmmvAsync::run must be exactly what your constructor requests. That is, it must be declared to receive a parameter of type void* (not LPTCSTR), and be a static member function (which it is, judging by your code). Since you are using names like LPTCSTR, you probably only want your code to run on Windows, so you don't need to worry about the distinction between void* and LPTCSTR.
If in doubt, make a wrapper:
void wrapper_jmmvAsync_run(void* par)
{
jmmvAsync::run(static_cast<LPTCSTR>(file));
}
...
LPTCSTR file = "file";
thread t(&wrapper_jmmvAsync_run, file);

callfunc in cocos2d-x

In cocos2d-x, the following piece of code is supposed to run the callback function after a delay. What do I need to do to fix the error?
bool LoadingLevelScreen::initialise() {
// set up the time delay
CCDelayTime *delayAction = CCDelayTime::actionWithDuration(0.5f);
// perform the selector call
CCCallFunc *callSelectorAction = CCCallFunc::actionWithTarget(
this, callfunc_selector( LoadingLevelScreen::menuCallbackStart ) );
// run the action
this->runAction( CCSequence::actions(
delayAction, callSelectorAction, NULL ) );
}
void LoadingLevelScreen::menuCallbackStart(CCObject * pSender)
{
}
Compiler Error:
error C2440: 'type cast' :
cannot convert from 'void (__thiscall LoadingLevelScreen::* )(cocos2d::CCObject *)'
to 'cocos2d::SEL_CallFunc'
Pointers to members have different representations; cannot cast between them
Either remove the CCObject* parameter in menuCallbackStart() method (because CCCallFunc::actionWithTarget() expects a method with no arguments), or change CCCallFunc to CCCallFuncO which expects a method with a CCObject* as argument, like so:
CCCallFuncO * callSelectorAction =
CCCallFuncO::create(this, &LoadingLevelScreen::menuCallbackStart, myObject);
where myObject is a CCObject * that will be passed to your method as the argument.
Note that callfunc_selector() is just a macro that typecasts your method to SEL_CallFunc:
#define callfunc_selector(MYSELECTOR) (SEL_CallFunc)(& (MYSELECTOR))
BTW ::actionWithTarget() is being deprecated, so use ::create() instead.
void LoadingLevelScreen::menuCallbackStart(CCObject * pSender)
{
}
should be
void LoadingLevelScreen::menuCallbackStart()
{
}
callfunc_selector is different with menu_selector, you don't need the CCObject* to pass in as a variable
if you do need to pass argument, please use callFuncND
this->runAction(Sequence::create(CallFunc::create(std::bind(&CNm::MNm, this)),NULL));
this->runAction(Sequence::create(CallFunc::create(std::bind(&ClassName::MethodName, this)),NULL));

I am new to threads, What does this compile error mean?

Using C++.
pthread_t threads[STORAGE]; // 0-99
...
void run()
Error>>> int status = pthread_create(&threads[0], NULL, updateMessages, (void *) NULL);
if (status != 0)
{
printf("pthread_create returned error code %d\n", status);
exit(-1);
}
...
void ClientHandler::updateMessages(void *)
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
...
Compile Error:
TCPClient.cpp:109: error: argument of type ‘void (ClientHandler::)(void*)’ does not match ‘void* (*)(void*)’
I can't figure out whats wrong.
Thanks in advance.
A pointer to a member function is different from a global function with the same signature since the member function needs an additional object on which it operates. Therefore pointers to these two types of functions are not compatible.
In this case this means that you cannot pass a member function pointer to pthread_create but only a pointer to a non-member (or static) function. A work around for this problem is to use the forth parameter of pthread_create to pass a pointer to a object to a global function which then calls the method of the passed object:
class ClientHandler {
public:
void updateMessages();
void run();
};
// Global function that will be the threads main function.
// It expects a pointer to a ClientHandler object.
extern "C"
void *CH_updateMessages(void *ch) {
// Call "real" main function
reinterpret_cast<ClientHandler*>(ch)->updateMessages();
return 0;
}
void ClientHandler::run() {
// Start thread and pass pointer to the current object
int status = pthread_create(&threads[0], NULL, CH_updateMessages, (void*)this);
...
}
It's nothing to do with threads, it's a normal C++ error, you're just passing an incompatible type of function pointer.
A function pointer is not the same as a member instance function pointer, even if their signature is the same; this is because there is an implicit reference to *this passed. You can't avoid this.
As pthread_create takes a free function, create a static function(is a free function) inside ClientHandler
static void Callback(void * this_pointer,int other_arg) {
ClientHandler* self = static_cast< ClientHandler*>(this_pointer);
self-> updateMessages(other_arg);
}
and call pthread_create as follows
pthread_create(&threads[0], NULL, &ClientHandler::Callback, (void *) pointer_to_ClientHandler,int other_arg);
That works because Callback is free function
YoLinux has a nice pthread tutorial that my help you in learning about threads.
As others have already said, the problem is that the signatures between the functions are different. Class member functions always have a "secret" extra parameter, the this pointer. So you can never pass a member function where a global function is expected. You can hack around this either with libraries such as Boost.Bind, or by making the function a static member of the class.
But the simplest, and most elegant solution is to use a different threading API.
Boost.Thread is a very nice threading library for C++ (pthreads is designed for C, and that's why it doesnt play well with C++ features such as class methods).
I'd recommend using that.
Your code could be rewritten as something like this:
class ClientHandler {
public:
ClientHandler(/* All the parameters you want to pass to the thread. Unlike pthreads you have complete type safety and can pass as many parameters to this constructor as you like */){...}
void operator()() // boost.thread calls operator() to run the thread, with no parameters. (Since all parameters were passed in the constructor and saved as member variables
{
string reqUpdate = "91"; // Request for update
string recvMSG;
while (true)
{
sleep(5);
sending(sock,reqUpdate); // send
recvMSG = receiving(sock); // receive
QString output(recvMSG);
emit signal_chat(output, 0); // Print message to text box
}
}
// whatever arguments you want to pass to the thread can be stored here as member variables
};
boost::threead_group gr; // can store all your threads here, rather than being limited to your fixed-size array
gr.create_thread(ClientHandler(/* construct a ClientHandler object with the parameters you like*/));
You're passing a member function instead of a global, normal, one.
Just define:
void updateMessages(void *) {
static ClientHandler c;
// use c..
}