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();
}
Related
I am writing a base class to manage threads. The idea is to allow the thread function to be overridden in child class while the base class manages thread life cycle. I ran into a strange behavior which I don't understand - it seems that the virtual function mechanism does not work when the call is made from a thread. To illustrate my problem, I reduced my code to the following:
#include <iostream>
#include <thread>
using namespace std;
struct B
{
thread t;
void thread_func_non_virt()
{
thread_func();
}
virtual void thread_func()
{
cout << "B::thread_func\n";
}
B(): t(thread(&B::thread_func_non_virt, this)) { }
void join() { t.join(); }
};
struct C : B
{
virtual void thread_func() override
{
cout << "C::thread_func\n";
}
};
int main()
{
C c; // output is "B::thread_func" but "C::thread_func" is expected
c.join();
c.thread_func_non_virt(); // output "C::thread_func" as expected
}
I tried with both Visual studio 2017 and g++ 5.4 (Ubuntu 16) and found the behavior is consistent. Can someone point out where I got wrong?
== UPDATE ==
Based on Igor's answer, I moved the thread creation out of the constructor into a separate method and calling that method after the constructor and got the desired behavior.
Your program exhibits undefined behavior. There's a race on *this between thread_func and C's (implicitly defined) constructor.
#include <iostream>
#include <thread>
using namespace std;
struct B
{
thread t;
void thread_func_non_virt()
{
thread_func();
}
virtual void thread_func()
{
cout << "B::thread_func\n";
}
B(B*ptr): t(thread(&B::thread_func_non_virt, ptr))
{
}
void join() { t.join(); }
};
struct C:public B
{
C():B(this){}
virtual void thread_func() override
{
cout << "C::thread_func\n";
}
};
int main()
{
C c; // "C::thread_func" is expected as expected
c.join();
c.thread_func_non_virt(); // output "C::thread_func" as expected
}
I have some 15-year-old C++ code that I am trying to bring up to more modern times. At this stage, I'm trying to get code that compiled with Visual C++ 6.0 to now compile with VS 2003 (Microsoft Visual C++ .NET 69462-335-0000007-18915). If we can get this to compile cleanly & run properly, then we can take another step to get it into a more recent version of VS. But I'm having a number of problems...
Here is a snippet of the (simplified) code:
class toS
{
public:
toS() { buff[0] ='\0'; }
operator LPCTSTR() { return buff; }
protected:
void Append (TCHAR c)
{
LPTSTR p = buff + _tcslen(buff);
*p++ = c;
*p = '\0';
}
TCHAR buff[40];
};
class LtoS : public toS
{
public:
LtoS(LONG n, TCHAR c = '\0')
{
_ltot(n, buff, 10);
Append(c);
}
};
void WriteBool(const CString& Section, const CString& Key, bool Value);
CString Section;
int nLine = 0;
std::vector<bool> *BoolVect;
std::vector<bool>::iterator vi;
...
for (vi = BoolVect->begin(); vi != BoolVect->end(); vi++)
WriteBool(Section, "LineVis " + LtoS(nLine++), *vi);
...
From this I get the following error message:
error C2677: binary '+' : no global operator found which takes type 'LtoS' (or there is no acceptable conversion)
Any idea how this code ever worked? If I can find out what it did in the past, I can begin to define the overloaded operator+ to match the functionality.
Compiler error goes away when I make class tos inherit from CString with:
class tos : public CString { ... }
Hopefully this will not only compile, but will execute correctly...
Deriving from several of the comments, try adding a public conversion operator to class toS as follows:
operator LPCTSTR() const { return &buff[0]; }
You may need to explicitly construct the string in the for loop as well, e.g.:
WriteBool(Section, CString("LineVis ") + static_cast<LPCTSTR>(LtoS(nLine++)), *vi);
(Side note: As you probably know since you just extracted code for an example, there's a problem here:
std::vector<bool> BoolVect;
...
for (vi = BoolVect->begin(); vi != BoolVect->end(); vi++)
The notation you're using to access the BoolVect implies that it is a pointer, but it's not being declared as such in your example.)
I am trying to follow the tutorial at http://www.drdobbs.com/cpp/ccli-threading-part-i/184402018 to do thread programming in winform in visual c++. I opened a win32 console project and added an empty cpp file to it inside which i placed the code as follows:
using namespace System;
using namespace System::Threading;
public class ThreadX{
int loopStart;
int loopEnd;
int dispFrequency;
public:
ThreadX(int startValue, int endValue, int frequency)
{
loopStart = startValue;
loopEnd = endValue;
dispFrequency = frequency;
}
void ThreadEntryPoint()
{
String^ threadName = Thread::CurrentThread->Name;
for (int i = loopStart; i <= loopEnd; ++i)
{
if ( i % dispFrequency == 0)
{
Console::WriteLine("{0} : i = {1,10}", threadName, i);
}
}
Console::WriteLine("{0} thread terminating", threadName);
}
};
int main()
{
ThreadX o1 = gcnew ThreadX(0, 1000000,200000);
Thread^ t1 = gcnew Thread(gcnew ThreadStart(o1, &ThreadX::ThreadEntryPoint));
t1->Name = "t1";
ThreadX o2 = gcnew ThreadX(-1000000, 0, 200000);
Thread^ t2 = gcnew Thread(gcnew ThreadStart(o2, &ThreadX::ThreadEntryPoint));
t1->Name = "t2";
t1->Start();
t2->Start();
Console::WriteLine("Primary Thread Terminating");
}
However this gives me errors such as :
error C2726: 'gcnew' may only be used to create an object with
managed type
error C2440: 'initializing' : cannot
convert from 'ThreadX *' to 'ThreadX' No constructor could take the
source type, or constructor overload resolution was ambiguous
error C3364: 'System::Threading::ThreadStart' : invalid argument for delegate constructor; delegate target needs to be a
pointer to a member function
You are mixing C++ and C++/CLI which is a different thing. Replace
public class ThreadX
with
public ref class ThreadX
I am getting multiple, confusing errors when building this school assignment and am hoping for some direction on what might be the problem. I wouldn't normally write it like this, but I put everything into one file as I try to debug this. Using Visual Studios Express 2012. I'm getting over 30 errors when I build, so I'm sure there is something fundamental that I am simply overlooking. Just a suggestion please, not looking for anyone to do my homework. Thanks
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include "MessageDisplayClass.h"
#include "LogMessageClass.h"
#include "TimerEventArgs.h"
using namespace System;
ref class CustomTimerClass
{
private:
static bool stopFlag = false;
// create instance of TimerEventArgs
TimerEventArgs^ timerEvent;
public:
CustomTimerClass(void)
{
}
delegate void CustomTimerClass::TimerAlarmHandler(/*Object^ sender, TimerEventArgs^ args*/);
event CustomTimerClass::TimerAlarmHandler^ OnTimerAlarm;
property bool StopFlag
{
bool get(void)
{
return stopFlag;
}
void set(bool b)
{
stopFlag = b;
}
}
void run()
{
Sleep(1000);
raiseTimerAlarm();
}
void OnStart()
{
// create instances of DisplayMessageClass and LogMessageClass classes
DisplayMessageClass^ messageDisplayer = gcnew DisplayMessageClass(this);
LogMessageClass^ messageLogger = gcnew LogMessageClass(this);
// display and log messages concerning this event
messageDisplayer->displayMessage(this, timerEvent);
messageLogger->logMessage(this, timerEvent);
}
void raiseTimerAlarm()
{
// create instance of TimerEventArgs and get time of instance creation
timerEvent = gcnew TimerEventArgs();
String^ eventTime = timerEvent->EventTime;
// tie this instance of CustomTimerClass to OnTimerAlarm event and start event
this->OnTimerAlarm += gcnew TimerAlarmHandler(this, &CustomTimerClass::OnStart);
OnTimerAlarm();
}
};
ref class MainProgram
{
int main(array<System::String ^> ^args)
{
CustomTimerClass^ timerClass = gcnew CustomTimerClass();
DisplayMessageClass^ messageClass = gcnew DisplayMessageClass();
LogMessageClass^ logerClass = gcnew LogMessageClass();
timerClass->run();
return 0;
}
};
At the point you're trying to use the various classes, the compiler doesn't know about them yet. Move your main() function to the end of the file. Or better, split your class definitions in their own header files and then include them in your main source file.
There are other related problems too. For example, you're trying to use the TimerEventArgs class before the compiler knows about it. So you need to move the class definition up. This is why it's best to have each class in its own header file, and then include it where needed. Though it's not strictly unnecessary, if you declare/define everything in the correct order.
Other than wrong order of declarations, it looks like the problem is that the compiler doesn't recognize the ^ bit, which suggests you're not compiling as C++/CLI. Righ-click the project in Solution Explorer and go to Configuration Properties -> General, and make sure that Common Language Runtime Support is set to Common Language Runtime Support (/clr).
For the benefit of anyone else (other newbies): As it turns out, my suspicion that the problem lay in the fact that some of the classes were "#including" each other was the problem. Using forward declarations, combined with having to create a separate class altogether to act as a variable storage handler was the solution to my problem.
Here are the two classes that were giving me the biggest problem, corrected to function correctly:
/*
CustomTimerClass.h
*/
#include "StdAfx.h"
#include "LogMessageClass.h"
#include "MessageDisplayClass.h"
#include "TimerEventArgs.h"
#include "Variables.h"
//ref class MessageDisplayClass;
//ref class Variables;
using namespace System;
ref class CustomTimerClass
{
private:
static bool stopFlag = false;
// create instance of TimerEventArgs
TimerEventArgs^ timerEvent;
// create instance of MessageDisplayClass and LogMessageClass
MessageDisplayClass^ messageDisplayer;
LogMessageClass^ messageLogger;
Variables^ flagVariable;
public:
CustomTimerClass(void)
{
}
delegate void CustomTimerClass::TimerAlarmHandler();
event CustomTimerClass::TimerAlarmHandler^ OnTimerAlarm;
property bool StopFlag
{
bool get(void)
{
return stopFlag;
}
void set(bool b)
{
stopFlag = flagVariable->Flag;
}
}
void run()
{
Sleep(1000);
raiseTimerAlarm();
}
void OnStart()
{
// create instances of DisplayMessageClass and LogMessageClass classes
messageDisplayer = gcnew MessageDisplayClass(this, flagVariable);
messageLogger = gcnew LogMessageClass(this);
// display and log messages concerning this event
messageDisplayer->displayMessage(this, timerEvent);
messageLogger->logMessage(this, timerEvent);
}
void raiseTimerAlarm()
{
// create instance of TimerEventArgs and get time of instance creation
timerEvent = gcnew TimerEventArgs();
String^ eventTime = timerEvent->EventTime;
// tie this instance of CustomTimerClass to OnTimerAlarm event and start event
this->OnTimerAlarm += gcnew TimerAlarmHandler(this, &CustomTimerClass::OnStart);
OnTimerAlarm();
}
};
/*
MessageDisplayClass serves to display a message that
represents the time at which the TimerEventArgs class is
instantiated. This time is returned through a function
of TimerEventArgs class.
*/
#pragma once
#include "stdafx.h"
#include <iostream>
#include "TimerEventArgs.h"
#include "Variables.h"
using namespace System;
ref class CustomTimerClass; // FORWARD DECLARATION HERE CAN
// ONLY BE USED FOR REFERENCE. CANNOT
// BE USED WHEN METHODS OF THE CLASS
// ARE CALLED
ref class MessageDisplayClass
{
private:
CustomTimerClass^ customTimerRef;
// Variables CLASS CREATED SOLELY TO ACT AS GO-BETWEEN BETWEEN
// MessageDisplayClass and CustomTimerClass
Variables^ variableRef;
static int counter;
public:
// constructor
MessageDisplayClass(CustomTimerClass^ CustomTimerClassInput, Variables^ variableReference)
{
customTimerRef = CustomTimerClassInput;
variableRef = gcnew Variables (CustomTimerClassInput);
}
void displayMessage(Object^ sender, TimerEventArgs^ timer)
{
counter ++;
if (counter > 0)
{
variableRef->Flag = true;
Console::WriteLine("Message: an event occured at time stamp: " + timer->EventTime);
}
}
};
I have a class such as :
class MyStreamReader
{
public:
MyStreamReader(MyPramameter myPram) {.....}
~MyStreamReader() {}
DWORD WINAPI ReaderThread(LPVOID *lpdwThreadParam )
{
//....
}
};
and i want to call ReaderThread with WinAPI CreateThread. But CreateThread wants ReaderThread function wants a static function.
In some forms it is said that this is possible with boost library such as :
CreateThread(NULL, 0, boost::bind(&MyStreamReader::ReaderThread,this),
(void*)&myParameterObject), 0, NULL);
But i got compilation error:
'CreateThread' : cannot convert parameter x from 'boost::_bi::bind_t<R,F,L>'
to 'LPTHREAD_START_ROUTINE'
So as a result my questions:
Is it possible to call non-static function of a class from
CreateThread using boost lib(or any other method)
If not any C++ THREADing librray you may recomend(for visual C++) which i can call-run non static member function of a class as a thread?
Best Wishes
Update:
So first question: It seesm that it is impossible to call non-static c++ member function from CreateThread win API...
So any recomandations for C++ Multithreading lib whic is possible to call non-static functions as threads...
Update 2:
Well i try boost thread lib...seems it works...
MyStreamReader* streamReader = new MyStreamReader(myParameters);
boost::thread GetStreamsThread
( boost::bind( &MyStreamReader::ReaderThread, streamReader ) );
or (no need for bind)
boost::thread GetStreamsThread(&MyStreamReader::ReaderThread, streamReader);
AND in order to use boost::thread i update my class definition as:
class MyStreamReader
{
public:
MyStreamReader(MyPramameter myPram) {.....}
~MyStreamReader() {}
void ReaderThread()
{
//....
}
};
One common answer to this is to use a static "thunk":
class Worker
{
public :
static DWORD Thunk(void *pv)
{
Worker *pThis = static_cast<Worker*>(pv);
return pThis->DoWork();
}
DWORD DoWork() { ... }
};
...
int main()
{
Worker worker;
CreateThread(NULL, 0, &Worker::Thunk, &worker);
}
You can, of course, pack more parameters into your call to pv. Just have your thunk sort them out correctly.
To answer your question more directly, boost::bind doesn't work with the Winapi that way. I would advise using boost::thread instead, which does work with boost::bind (or, if you have a C++0x compiler, use std::thread with std::bind).