How to use "this" in a thread! - multithreading

I am trying to call my static function using a separate thread, I have in my function something like this->listBox1->Items->Add(s);. The compiler shows that I can't use this inside a static function. I tried to make my function non-static (i.e remove static keyword) but when I did that, again the compiler shows two errors which are:
Error 2 error C3350: 'System::Threading::ThreadStart' : a delegate constructor expects 2 argument(s) c:\users\ahmed\documents\visual studio 2010\projects\testscan\testscan\Form1.h 116
Error 1 error C2276: '&' : illegal operation on bound member function expression c:\users\ahmed\documents\visual studio 2010\projects\testscan\testscan\Form1.h 116
Edit:
The function:
void ScanMyDir(String^ SourceDir)
{
array <String^> ^fileEntries = Directory::GetFiles(SourceDir);
for each (String^ fileName in fileEntries)
this->Form1->listBox1->Items->Add(fileName);
array<String^> ^SubDirEntries = Directory::GetDirectories(SourceDir);
for each (String^ subdir in SubDirEntries)
if ((File::GetAttributes(subdir) & FileAttributes::ReparsePoint)!= FileAttributes::ReparsePoint)
ScanMyDir(subdir);
}
Way to call it:
void button1_Click(System::Object^ sender, System::EventArgs^ e) {
Thread ^thr1 = gcnew Thread(gcnew ParameterizedThreadStart(this,&Form1::ScanMyDir));
thr1->Start("c:\\");
}
Modification on Form load:
void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
System::Windows::Forms::Control::CheckForIllegalCrossThreadCalls = false;
}
The new errors :( :
Error 5 error C3352: 'void testScan::Form1::ScanMyDir(System::String ^)' : the specified function does not match the delegate type 'void (System::Object ^)' c:\users\ahmed\documents\visual studio 2010\projects\testscan\testscan\Form1.h 117
Error 1 error C2273: 'function-style cast' : illegal as right side of '->' operator c:\users\ahmed\documents\visual studio 2010\projects\testscan\testscan\Form1.h 105
Error 2 error C2227: left of '->listBox1' must point to class/struct/union/generic type c:\users\ahmed\documents\visual studio 2010\projects\testscan\testscan\Form1.h 105
Error 3 error C2227: left of '->Items' must point to class/struct/union/generic type c:\users\ahmed\documents\visual studio 2010\projects\testscan\testscan\Form1.h 105
Error 4 error C2227: left of '->Add' must point to class/struct/union/generic type c:\users\ahmed\documents\visual studio 2010\projects\testscan\testscan\Form1.h 105

No need to make your function static. Given errors are due to the wrong syntax you are using.
Assuming your form type as FormType,
void ScanMyDir()
{
//....
}
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
Thread ^thr1 =gcnew Thread(gcnew ThreadStart(this,&FormType::ScanMyDir));
thr1->Start();
}
If you insist on making it static, like #jgauffin said pass the form as an Object parameter to ScanMyDir() and then recast it to form in the function.
static void ScanMydir(Object ^ param)
{
FormType ^ ft = static_cast<FormType^>(param);
//..
ft->listBox1->Items->Add(fileName);
//..
}
In this case you have to use ParametrizedThreadStart()
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
Thread ^thr1 =gcnew Thread(gcnew ParametrizedThreadStart(&FormType::ScanMyDir));
// it is static no need for "this"
thr1->Start(this);
}
But at least make the ScanMyDir() function private and prevent outside access.
Now probably you will have another error, saying "you can not touch GUI with different threads", then on your forms loading function write
void FormType_Load(Object ^sender, EventArgs ^ e)
{
System::Windows::Forms::Control::CheckForIllegalCrossThreadCalls = false;
//....
}
But this may be dangerous depending on your implementation, you have to guarantee the thread-safety of listbox1->items.
Also listen to what the #Yochai Timmer guy said. He is telling good things.

Ok, basic principles:
Static means that the method is NOT a member of the object. It's a member of the Class type, and is in common to all the objects of that class. So, there's no this because there's no object associated.
Read the compiler errors. Read the function definitions to pass th right parameters...
When you get this working, you'll probably have an error because you're trying to use GUI function's from a different thread. That will cause run-time errors (sometimes).
Check this: UI Thread .Invoke() causing handle leak?

Disclaimer: I haven't used managed C++, only C# and vanilla C++. Therefore this answer might be incorrect.
ThreadStart delegate can take a parameter. Pass the instance of your class to it and cast it to your class in the static thread method. It's not this, but almost the same thing.

Related

How do I access a form's control from another thread?

Using VC++ 2010.
I want to access a form's control from a class in another thread.. and can't figure out the best (or any) way to do this. How can I pass a reference of my form instance? Im using createthread() as opposed to the managed version, wanting to make my app compatible with XP.
I've tried passing a reference and other values in a struct through the lpParameter, but I can't seem to figure out how to declare the reference properly.
ref class SZClass {
private:
FMain ^bound_form;
int server_port;
public:
void BindForm(FMain ^bf);
void Initialize(int sp)
}
struct param_data {
public:
FMain ^form_tobind;
int port_num;
}
are giving me errors:
error C2143: syntax error : missing ';' before '^'
FMain is the name of my form class, and I have a delegate method already set up to make it multithread safe:
public:
FMain(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
void FMain::PrintConsole(std::string mzg) {
String ^Smzg = marshal_as<String^>(mzg);
if (this->textBox1->InvokeRequired) {
SetTextDelegate^ d = gcnew SetTextDelegate(this, &FMain::PrintConsole);
this->Invoke(d, gcnew array<Object^> { Smzg });
} else {
textBox1->Text += Smzg;
textBox1->SelectionStart = textBox1->TextLength;
}
}
How do I declare a reference to my form?
Or is there an easier or better way to do this?
I don't know what forms library you're using, but the general rule of thumb for your question is, "Don't."
Unless you have a peculiar GUI library, Windows UI is thread-affinitized. All access to UI elements should be done via the ui's affinitized thread. Manipulating UI state from an unaffinitized execution context should be done by marshaling the update request to the affinitized context. It should not be done directly.

warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)

This particular warning, generated on compiling my vc++ code in VS 2008 is bugging me for a while. On going through related posts in SO and in microsoft forums for this warning, It is advised to disable the warning using pragma warning, But is there a way to fix this issue without a warning pragma?
class CBLockException : public CBException
{
public:
// Constructor
CBLockException();
CBLockException(const char *tag);
CBLockException(const char *func, const char *tag, const char *msg = NULL);
};
class CLASS_DECL_BASEOBJECTS CBLock : public CBObject
{
public:
enum Locktype { READLOCK, WRITELOCK };
CBLock() throw (CBLockException*); // C4290
virtual ~CBLock();
void Lock(Locktype lockType = WRITELOCK);
void Unlock(Locktype lockType = WRITELOCK);
private:
class LockImplementation;
LockImplementation *lockImp;
};
class CBLock::LockImplementation
{
public:
LockImplementation() throw (CBLockException*); //C4290
~LockImplementation();
CRITICAL_SECTION csExclusive;
CRITICAL_SECTION csReader;
HANDLE hevReadDone;
int cReader;
};
But is there a way to fix this issue without a warning pragma?
Yes. Delete the throw specification. It does not do what you think it does. Instead, it is mostly useless.
Specifically, writing:
CBLock() throw (CBLockException*);
…
CBLock::CBLock() { /* … */ }
is essentially equivalent to
CBLock();
…
CBLock::CBLock() {
try {
/* … */
} catch(CBLockException*&) { // Yes, like this! Stop throwing exceptions by pointer, please!
throw;
} catch(...) {
throw std::bad_exception();
}
}
(actually, with constructor it will be equivalent to the function try block, but I don't want to complicate it further with yet another C++ wart)
In particular, notice it does not actually check that the block is not throwing any other kind of exception. The only thing it does is convert any other exception to a totally useless std::bad_exception, throwing any useful information away in the process.
The recommended fix is to convert any throw declarations to documentation comments!
Also note that this applies even to the throw() specification. The only useful thing is the nothrow specification introduced in C++11, which actually checks the function won't throw any C++ exception, ever, and it's earlier MSC++-specific __declspec(nothrow) equivalent.
Go to project Property Pages -> Configuration Properties -> C/C++ -> Advanced -> Disable Specific Warnings -> Edit
Enter codes of warnings to be disabled separated by semicolon (in your case 4290 without the leading "C")
Source: http://msdn.microsoft.com/en-us/library/jj715718.aspx

Error while building the solution in vs2012?

I've created my project in vs2008.It works fine.But when i opened the solution and try to build it in vs2012 i am getting the following error in TransactionDB.dbml page.
a partial method may not have multiple defining declarations
What could be the problem??
.net supports partial methods.
It means you write a definition in one part of the partial class and the implementation in another. Like this:
partial class MyClass
{
partial void MyPartialMethod(string s);
}
// This part can be in a separate file.
partial class MyClass
{
// Comment out this method and the program will still compile.
partial void MyPartialMethod(string s)
{
Console.WriteLine("Something happened: {0}", s);
}
}
In your case I you have the two definitions of the partial method causing the compiler to fail.
Source MSDN
The defining declaration of a partial method is the part that specifies the method signature, but not the implementation (method body). A partial method must have exactly one defining declaration for each unique signature. Each overloaded version of a partial method must have its own defining declaration.
To correct this error
Remove all except one defining declaration for the partial method.
Example
// cs0756.cs
using System;
public partial class C
{
partial void Part();
partial void Part(); // CS0756
public static int Main()
{
return 1;
}
}

C++.net Delegate not working - compiler error

Right I created a new thread from a static function from the same class.
Inside the same class I try to call a delegate to update the GUI.
I get a compiler error saying:
Invalid delegate initializer - an object is needed in addition to a function.
At &MainUi::AddListItemMethod.
delegate void AddListItem(void);
public: void AddListItemMethod(String^ myString)
{
ListView1->Items->Add(myString);
}
private: static void SecondThread()
{
AddListItem^ del = gcnew AddListItem(&MainUI::AddListItemMethod);
del->Invoke("test");
}
I don't know why it doesn't work. I also tried this and still failed. Any help please?
Invoke(gcnew AddListItem(MainUI::&AddListItemMethod), "test");
Either You have to make Listview1 static to work or you should create an instance/object of MainUI class to access a non static method of that class.
Thank you and Happy coding.

QtConcurrent::map() with member function = can not compile

My project is to create a small program which demonstrates the work of a search engine: indexing and returning result for arbitrary queries. I've done the work with the indexer part and now I want to improve it with indexing multiple files at once. The MainWindow class is here:
class MainWindow : public QMainWindow
{
Q_OBJECT
.....
private:
Indexer * indexer;
QStringList fileList;
....
void index(QStringList list);
void add(const QString &filename);
}
This is the implementation of add (add need to access fileList to avoid index the same files again, thus it can not be static method):
void MainWindow::add(const QString &filename)
{
if (!fileList.contains(filename))
{
indexer->addDocument(filename.toStdString());
fileList.append(filename);
qDebug() << "Indexed" << filename;
emit updatedList(fileList);
}
}
The implement of index method is to receive a file lists and call add upon each file name:
void MainWindow::index(QStringList list)
{
....
QtConcurrent::map(list, &MainWindow::add);
....
}
The error I receive when compiling these code is:
usr/include/qt4/QtCore/qtconcurrentmapkernel.h: In member function 'bool QtConcurrent::MapKernel<Iterator, MapFunctor>::runIteration(Iterator, int, void*) [with Iterator = QList<QString>::iterator, MapFunctor = QtConcurrent::MemberFunctionWrapper1<void, MainWindow, const QString&>]':
../search-engine/mainwindow.cpp:361:1: instantiated from here
/usr/include/qt4/QtCore/qtconcurrentmapkernel.h:73:9: error: no match for call to '(QtConcurrent::MemberFunctionWrapper1<void, MainWindow, const QString&>) (QString&)'
/usr/include/qt4/QtCore/qtconcurrentfunctionwrappers.h:128:7: note: candidate is:
/usr/include/qt4/QtCore/qtconcurrentfunctionwrappers.h:138:14: note: T QtConcurrent::MemberFunctionWrapper1<T, C, U>::operator()(C&, U) [with T = void, C = MainWindow, U = const QString&]
/usr/include/qt4/QtCore/qtconcurrentfunctionwrappers.h:138:14: note: candidate expects 2 arguments, 1 provided
I'm not really familiar with how QtConcurrent works, and the documentation doesn't provide much details about it. I really hope that someone here can help. Thanks in advance.
To be able to call a pointer-to-member, you need, in addition to that functions formal arguments, an instance of that class (the this pointer that you get inside member functions).
There are two ways to handle this: create a simple functor to wrap the call, or use a lambda.
The functor would look like this:
struct AddWrapper {
MainWindow *instance;
AddWrapper(MainWindow *w): instance(w) {}
void operator()(QString const& data) {
instance->add(data);
}
};
And you'd use it like:
AddWrapper wrap(this);
QtConcurrent::map(list, wrap);
(Careful with the lifetime of that wrapper though. You could make that more generic - you could also store a pointer-to-member in the wrapper for instance, and/or make it a template if you want to reuse that structure for other types.)
If you have a C++11 compiler with lambdas, you can avoid all that boilerpalte:
QtConcurrent::map(list, [this] (QString const& data) { add(data); });
Note: I'm not sure how QtConcurrent::MemberFunctionWrapper1 got involved in your example, I'm not seeing it here. So there might be a generic wrapper already in Qt for this situation, but I'm not aware of it.

Resources