When one create a new thread, using ThreadStart() how does one pass multiple arguments to the function?
Here's an example:
using namespace System;
using namespace System::Threading;
public ref class Animal
{
public:
void Hungry(Object^ food, int quantity);
};
void Animal::Hungry(Object^ food, int quantity)
{
Console::WriteLine("The animal eats " + quantity.ToString() + food);
}
void main()
{
Animal^ test = gcnew Animal;
Thread^ threads = gcnew Thread(gcnew ParameterizedThreadStart(test, &Animal::Hungry));
threads->Start("Grass", 1); //need to pass 2nd argument!
}
It works fine with just one argument (if I remove int quantity and just have Object^ food) since ParameterizedThreadStart takes only an Object^
Like in any other situation where you have to put multiple values into one object, you either:
create a wrapper class or struct (the clean way)
or use some predefined one like Tuple (the lazy way)
Here's the lazy way:
void Animal::Hungry(Object^ param)
{
auto args = safe_cast<Tuple<String^, int>^>(param);
Console::WriteLine("The animal eats {1} {0}", args->Item1, args->Item2);
}
void main()
{
Animal^ test = gcnew Animal;
Thread^ threads = gcnew Thread(gcnew ParameterizedThreadStart(test, &Animal::Hungry));
threads->Start(Tuple::Create("Grass", 1));
}
Related
I am trying to construct a child class object from a base class object. I have tried the below code.
class A
{
public:
A();
A(A&& objectName) = default;
virtual void setint(int i);
virtual void getint();
int var;
};
class B: public A
{
public:
virtual void getint();
B(A&& objectName);
int j= 20;
};
A::A()
{
}
void A::setint(int i)
{
var = i;
}
void A::getint()
{
qDebug()<<"From A Var"<<var;
}
void B::getint()
{
qDebug()<<"From B j"<<j;
qDebug()<<"From B Var"<<var;
}
B::B(A&& objectName): A(std::move(objectName))
{
}
And in my Main.cpp I am doing this
#include <memory>
int main(int argc, char *argv[])
{
A *obj = new A();
obj->setint(10);
obj->getint();
A *obj1 = new B(std::move(*obj));
obj->getint();
obj1->getint();
return 0;
}
The result I get is
From A Var 10
From A Var 10
From B j 20
From B Var 10
My question is why am I getting the value of Var after A *obj1 = new B(std::move(*obj)); this line. I thought the object pointed by obj must have been destructed.
Let me copy paste from this answer: https://stackoverflow.com/a/15663912/512225
std::move doesn't move from the object. It just returns an rvalue reference whose referand is the object, making it possible to move from the object.
Anyway your code is terrible. I hope you know. If you don't, ask for a review.
I'm facing a problem while creating a Singleton class with it's own thread that sends signal to another thread which is not a singleton class.
Consumer.h
class Consumer : public QThread
{
Q_OBJECT
public:
explicit Consumer(QObject *parent = 0);
Consumer(Worker *Worker);
signals:
void toMessage(const bool& keepCycle);
public slots:
void getMessage(const QString& str);
private:
int m_counter;
};
Consumer.cpp
Consumer::Consumer(QObject *parent) :
QThread(parent)
{
m_counter = 0;
connect(Worker::Instance(), SIGNAL(sendMessage(QString)), this, SLOT(getMessage(QString)));
connect(this, SIGNAL(toMessage(bool)), Worker::Instance(), SLOT(fromMessage(bool)));
}
// Get's message from Singleton thread if counter > 5 sends signal to terminate cycle in Singleton thread
void Consumer::getMessage(const QString &str)
{
m_counter++;
if(m_counter <= 5) {
qDebug() << "Got message " << m_counter << ": " << str << "\n";
return;
}
else {
emit toMessage(false);
}
}
Singleton is done as follows (suspect it's Not Thread-safe):
template <class T>
class Singleton
{
public:
static T* Instance()
{
if(!m_Instance) m_Instance = new T;
assert(m_Instance != NULL);
return m_Instance;
}
protected:
Singleton();
~Singleton();
private:
Singleton(Singleton const&);
Singleton& operator=(Singleton const&);
static T* m_Instance;
};
template <class T> T* Singleton<T>::m_Instance = NULL;
And Worker Singleton class
class Worker : public QThread
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
void run();
signals:
void sendMessage(const QString& str);
public slots:
void fromMessage(const bool& keepCycle);
private:
volatile bool m_keepCycle;
};
typedef Singleton<Worker> Worker;
Worker.cpp
Worker::Worker(QObject *parent) :
QThread(parent)
{
m_keepCycle = true;
}
void Worker::run()
{
while(true) {
if(m_keepCycle) {
QString str = "What's up?";
ElWorker::Instance()->sendMessage(str);
}
else {
qDebug() << "Keep Alive" << false;
break;
}
}
qDebug() << "Value of keepCycle" << m_keepCycle;
}
void Worker::fromMessage(const bool &keepCycle)
{
m_keepCycle = keepCycle;
qDebug() << "\nMessage FROM: " << keepCycle << "\n";
}
The main.cpp
Consumer consumer;
ElWorker::Instance()->start();
consumer.start();
Can you help me to create thread-safe Singleton and to send signals between threads?
First of all, it is highly recommended to separate worker from it's thread:
class Object : public QObject
{
...
public slots:
void onStarted(); // if needed
void onFinished(); // if needed
...
};
...
mObject = QSharedPointer < Object >(new Object);
mThread = new QThread(this);
mObject->moveToThread(mThread);
connect(mThread, SIGNAL(started()), mObject, SLOT(onStarted())); // if needed
connect(mThread, SIGNAL(finished()), mObject, SLOT(onFinished())); // if needed
mThread->start();
Second of all, there are a lot of ways of creating a singleton. My favourite is this:
Object * obj(QObject *parent = 0)
{
static Object *mObj = new Object(parent);
return mObj;
}
...
obj(this); // creating
obj()->doStuff(); // using
Now, about thread-safety. Sending signals is thread-safe, unless you're sending pointers or non-constant references. Which, according to your code, you are not. So, you should be fine.
UPDATE
Actually, I didn't get how created thread-safe singleton above and I'm
sending a signal from Worker TO Consumer Not a Thread itself? – hiken
Static values inside of function are created and initialized only once, so the first time you call obj function mObj is created and returned and each other time you call it, previously created mObj is returned. Also, I didn't say, it's thread-safe, all I said - I like this way better, then template one, because:
it is simplier
requires less code
works with QObject without problems
Yes, you should send signals from worker class, not thread one. Qt's help has a good example (the first one, not the second one): http://doc.qt.io/qt-5/qthread.html#details. The only thing QThread should be used for - is controlling thread's flow. There are some situations, when you need to derive from QThread and rewrite QThread::run, but your case isn't one of them.
I have a question concerning working with classes in c++. I must say I'm a beginner. For example, i have this class:
class student {
private:
char* name;
public:
int nrcrt;
student() {
name = new char[7];
name = "Anonim";
nrcrt = 0;
}
student(char* n, int n) {
this->name = new char[7];
strcpy(name, n);
nrcrt = nr;
}
~student() {
delete [] name;
}
char* get_name() {
return this->name;
}
}
void main() {
student group[3];
group[0] = student("Ana", 1);
group[1] = student("Alex", 2);
group[2] = student("Liam", 5);
for (i=0; i<3; i++) {
if (group.nrcrt[i] != 0)
cout << group[i].get_name() << Endl;
}
}
My question is why is it displaying different characters?
first of all your code is not working.
3.cpp:40:18: error: request for member ‘nrcrt’ in ‘group’, which is of non-class type ‘student [3]’
if(group.nrcrt[i]!=0)
i is also not declared.please make proper changes.
group.nrcrt[i]
should be changed to:
group[i].nrcrt
When the array is created, your default constructor is used.
When you assign to the elements, your destructor is called, deleting name.
The default constructor is assigning a literal to name, and deleting that memory has undefined behaviour.
In your default constructor, replace
name = "Anonim";
with
strcpy(name, "Anonim");
Your compiler should have warned you about the assignment.
If it didn't, increase the warning level of your compiler.
If it did, start listening to your compiler's warnings.
do not worry. C++ could look a bit scary as first but it is ok when you get into it. First, let's say that all classes it is good to start with upper case letters. Secondly, you have two constructors (default without parameters and one or more with, in our case one). Default consructor you need to declare an array of objects:
Student group[3];
The next important thing is that you then do not need the rest of the constructors in that case.
group[0]=student("Ana",1);
group[1]=student("Alex",2);
group[2]=student("Liam",5);
Remember to include ; at the end of class declaration. To put all the statements and expression throughout your interation within the same loop. Here is what I found as an errors anf fix them. Could probably have more.
class Student
{
private:
char* name;
public:
int nrcrt;
Student()
{
name=new char[7];
strcpy(name, "Anonim");
nrcrt=0;
}
Student( char* n, int n)
{
this->name=new char[7];
strcpy(name, n);
nrcrt=nr;
}
~Student()
{
delete [] name;
}
char* get_name()
{
return this->name;
}
};
int main()
{
Student group[3];
for(int i=0;i<3;i++)
{
if(group.nrcrt[i]!=0)
cout<<group[i].get_name()<<endl;
}
return 0;
}
I've just started experiencing with thread and can't get some basics. How can i write to Console from thread with interval say 10 msec? So i have a thread class:
public ref class SecThr
{
public:
DateTime^ dt;
void getdate()
{
dt= DateTime::Now;
Console::WriteLine(dt->Hour+":"+dt->Minute+":"+dt->Second);
}
};
int main()
{
Console::WriteLine("Hello!");
SecThr^ thrcl=gcnew SecThr;
Thread^ o1=gcnew Thread(gcnew ThreadStart(SecThr,&thrcl::getdate));
}
I cannot compile it in my Visual c++ 2010 c++ cli, get a lot of errors C3924, C2825, C2146
You are just writing incorrect C++/CLI code. The most obvious mistakes:
missing using namespace directives for the classes you use, like System::Threading, required if you don't write System::Threading::Thread in full.
using the ^ hat on value types like DateTime, not signaled as a compile error but very detrimental to program efficiency, it will cause the value to be boxed.
not constructing a delegate object correctly, first argument is the target object, second argument is the function pointer.
Rewriting it so it works:
using namespace System;
using namespace System::Threading;
public ref class SecThr
{
DateTime dt;
public:
void getdate() {
dt= DateTime::Now;
Console::WriteLine(dt.Hour + ":" + dt.Minute + ":" + dt.Second);
}
};
int main(array<System::String ^> ^args)
{
Console::WriteLine("Hello!");
SecThr^ thrcl=gcnew SecThr;
Thread^ o1=gcnew Thread(gcnew ThreadStart(thrcl, &SecThr::getdate));
o1->Start();
o1->Join();
Console::ReadKey();
}
I have the following in my WinRT component:
public value struct WinRTStruct
{
int x;
int y;
};
public ref class WinRTComponent sealed
{
public:
WinRTComponent();
int TestPointerParam(WinRTStruct * wintRTStruct);
};
int WinRTComponent::TestPointerParam(WinRTStruct * wintRTStruct)
{
wintRTStruct->y = wintRTStruct->y + 100;
return wintRTStruct->x;
}
But, it seems that the value of winRTStruct->y and x are always 0 inside the method, when called from C#:
WinRTComponent comp = new WinRTComponent();
WinRTStruct winRTStruct;
winRTStruct.x = 100;
winRTStruct.y = 200;
comp.TestPointerParam(out winRTStruct);
textBlock8.Text = winRTStruct.y.ToString();
What is the correct way to pass a struct by reference so it an be updated inside the method of a WinRTComponent written in C++/CX?
You cannot pass a struct by reference. All value types (including structs) in winrt are passed by value. Winrt structs are expected to be relatively small - they're intended to be used for holding things like Point and Rect.
In your case, you've indicated that the struct is an "out" parameter - an "out" parameter is write-only, its contents are ignored on input and are copied out on return. If you want a structure to be in and out, split it into two parameters - one "in" parameter and another "out" parameter (in/out parameters are not allowed in WinRT because they don't project to JS the way you expect them to project).
My co-worker helped me solve this.
In WinRT components, it seems that the best way to do this is to define a ref struct instead of a value struct:
public ref struct WinRTStruct2 sealed
{
private: int _x;
public:
property int X
{
int get(){ return _x; }
void set(int value){ _x = value; }
}
private: int _y;
public:
property int Y
{
int get(){ return _y; }
void set(int value){ _y = value; }
}
};
But this creates other problems. Now the VS11 compiler gives INTERNAL COMPILER ERROR when I try to add a method to the ref struct that returns an instance of the struct.