在 C++ Builder 中使用 lambda 将参数传递给 TThread::Queue
Passing parameters to TThread::Queue using lambda in C++ Builder
我想做这样的事情:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
TThread::Queue( nullptr, [&]() -> void { Form2->SetMsg(fMsg); } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
所以我只是调用 SetMsg("mymessage");
并且无论在哪个线程中调用它都会正确打印。除了 UnicodeString
在调用 lambda 之前被释放外,上面的方法是可行的。
据我了解,上面的 lambda 应该保持这种形式分配,如果我在 lambda 本身而不是 fMsg 参数中硬编码字符串,它确实有效。那我怎么传参呢?
我可以用 new 分配它,然后再用 delete 分配它,但由于某种原因也失败了。
我试过了:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
UnicodeString* p = new UnicodeString(fMsg);
TThread::Queue( nullptr, [&]() -> void { try { Form2->SetMsg(*p); } __finally { delete p; } } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
使用 TThread::CreateAnonymousThread
会更快(更便宜)还是更容易?
如果使用 TThread::Synchronize
,第一个版本工作正常,但我想避免线程阻塞。
The above would work except the UnicodeString
gets deallocated before lambda is called.
您的 lambda 正在通过引用 捕获 UnicodeString
,因此当 SetMsg()
退出时,UnicodeString
将被销毁,留下引用在 lambda 内部悬空。 lambda 需要通过值 捕获 UnicodeString
而不是制作自己的 copy.
此外,我不建议使用全局 Form2
变量来调用 SetMsg()
,我会使用 lambda 捕获 SetMsg
的 this
指针。
试试这个:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
TThread::Queue( nullptr, [this, fMsg]{ this->SetMsg(fMsg); } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
或者,不要第二次调用 lambda 调用 SetMsg()
,只需直接访问 Memo
,因为您知道 GetCurrentThreadId()
检查此时将是多余的:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
TThread::Queue( nullptr, [this, fMsg]{ this->Memo1->Lines->Add(fMsg); } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
I could allocate it with new
and delete
later, but that fails for some reason too.
您的 lambda 正在通过引用 捕获指针 ,因此当 SetMsg()
退出时,您将 lambda 中的引用悬空。你需要通过值来捕获指针而不是:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
UnicodeString* p = new UnicodeString(fMsg);
TThread::Queue( nullptr, [this, p]{ try { this->SetMsg(*p); /* or: this->Memo1->Lines->Add(*p); */ } __finally { delete p; } } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
一般来说,使用动态 UnicodeString
会起作用,但我强烈建议捕获 std::unique_ptr
或 std::shared_ptr
来为您处理重新分配,而不是使用手动try/__finally
块:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
// using unique_ptr, must be moved into the lambda
auto p = std::make_unique<UnicodeString>(fMsg);
TThread::Queue( nullptr, [this, p = move(p)]{ this->SetMsg(*p); /* or: this->Memo1->Lines->Add(*p); */ } );
// using shared_ptr, can be copied by value
auto p = std::make_shared<UnicodeString>(fMsg);
TThread::Queue( nullptr, [this, p]{ this->SetMsg(*p); /* or: this->Memo1->Lines->Add(*p); */ } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
Would it be faster (less expensive) or easier with the TThread::CreateAnonymousThread
?
没有。调用 Queue()
时,您已经 运行 在一个线程中,没有理由浪费开销来生成另一个线程。而且您仍然需要处理将值复制到该线程的 lambda/callback 函数中的问题。
我想做这样的事情:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
TThread::Queue( nullptr, [&]() -> void { Form2->SetMsg(fMsg); } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
所以我只是调用 SetMsg("mymessage");
并且无论在哪个线程中调用它都会正确打印。除了 UnicodeString
在调用 lambda 之前被释放外,上面的方法是可行的。
据我了解,上面的 lambda 应该保持这种形式分配,如果我在 lambda 本身而不是 fMsg 参数中硬编码字符串,它确实有效。那我怎么传参呢?
我可以用 new 分配它,然后再用 delete 分配它,但由于某种原因也失败了。
我试过了:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
UnicodeString* p = new UnicodeString(fMsg);
TThread::Queue( nullptr, [&]() -> void { try { Form2->SetMsg(*p); } __finally { delete p; } } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
使用 TThread::CreateAnonymousThread
会更快(更便宜)还是更容易?
如果使用 TThread::Synchronize
,第一个版本工作正常,但我想避免线程阻塞。
The above would work except the
UnicodeString
gets deallocated before lambda is called.
您的 lambda 正在通过引用 捕获 UnicodeString
,因此当 SetMsg()
退出时,UnicodeString
将被销毁,留下引用在 lambda 内部悬空。 lambda 需要通过值 捕获 UnicodeString
而不是制作自己的 copy.
此外,我不建议使用全局 Form2
变量来调用 SetMsg()
,我会使用 lambda 捕获 SetMsg
的 this
指针。
试试这个:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
TThread::Queue( nullptr, [this, fMsg]{ this->SetMsg(fMsg); } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
或者,不要第二次调用 lambda 调用 SetMsg()
,只需直接访问 Memo
,因为您知道 GetCurrentThreadId()
检查此时将是多余的:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
TThread::Queue( nullptr, [this, fMsg]{ this->Memo1->Lines->Add(fMsg); } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
I could allocate it with
new
anddelete
later, but that fails for some reason too.
您的 lambda 正在通过引用 捕获指针 ,因此当 SetMsg()
退出时,您将 lambda 中的引用悬空。你需要通过值来捕获指针而不是:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
UnicodeString* p = new UnicodeString(fMsg);
TThread::Queue( nullptr, [this, p]{ try { this->SetMsg(*p); /* or: this->Memo1->Lines->Add(*p); */ } __finally { delete p; } } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
一般来说,使用动态 UnicodeString
会起作用,但我强烈建议捕获 std::unique_ptr
或 std::shared_ptr
来为您处理重新分配,而不是使用手动try/__finally
块:
void TForm2::SetMsg(UnicodeString fMsg)
{
// If thread is not main Queue...
if (GetCurrentThreadId() != System::MainThreadID)
{
// using unique_ptr, must be moved into the lambda
auto p = std::make_unique<UnicodeString>(fMsg);
TThread::Queue( nullptr, [this, p = move(p)]{ this->SetMsg(*p); /* or: this->Memo1->Lines->Add(*p); */ } );
// using shared_ptr, can be copied by value
auto p = std::make_shared<UnicodeString>(fMsg);
TThread::Queue( nullptr, [this, p]{ this->SetMsg(*p); /* or: this->Memo1->Lines->Add(*p); */ } );
return;
}
// If thread is main then print directly...
Memo1->Lines->Add(fMsg);
}
Would it be faster (less expensive) or easier with the
TThread::CreateAnonymousThread
?
没有。调用 Queue()
时,您已经 运行 在一个线程中,没有理由浪费开销来生成另一个线程。而且您仍然需要处理将值复制到该线程的 lambda/callback 函数中的问题。