Multithreading 使用什么代替TThread.Suspend()
假设我有一个工作线程,它填充主线程中声明的一个大向量。当工作线程仍在运行(响应用户交互)时,我希望主线程检查向量是否已填充到特定大小。如果有,我希望它从向量中提取一些值。如果没有,我希望它等待工作线程填充到所需的大小 由于工作线程可能仍在向向量添加项目(可能会导致调整大小/移动),我认为我只能在工作线程挂起但TThread.Suspend()不推荐时执行此操作。我花了好几天的时间研究了TMutex、TSemaphore等,但文档非常糟糕。谁能给我指一下正确的方向吗 一种可能的解决方案是在工作线程中填充一个单独的较小的向量,然后使用synchronize将其附加到较大的向量(等等),但我希望避免这种情况 由于工作线程可能仍在向向量添加项目(可能导致调整大小/移动),我认为我只能在工作线程挂起时执行此操作 这是一个非常好的主意 但不推荐使用TThread.Suspend() 即使它没有被弃用,使用它仍然是危险的。只有调试器才应该挂起线程,这就是Multithreading 使用什么代替TThread.Suspend(),multithreading,c++builder,Multithreading,C++builder,假设我有一个工作线程,它填充主线程中声明的一个大向量。当工作线程仍在运行(响应用户交互)时,我希望主线程检查向量是否已填充到特定大小。如果有,我希望它从向量中提取一些值。如果没有,我希望它等待工作线程填充到所需的大小 由于工作线程可能仍在向向量添加项目(可能会导致调整大小/移动),我认为我只能在工作线程挂起但TThread.Suspend()不推荐时执行此操作。我花了好几天的时间研究了TMutex、TSemaphore等,但文档非常糟糕。谁能给我指一下正确的方向吗 一种可能的解决方案是在工作线程
SuspendThread()
API的目的
我花了好几天的时间研究了TMutex、TSemaphore等,但文档非常糟糕。谁能给我指一下正确的方向吗
您可以简单地用or包装对向量的所有访问,然后主线程和工作线程都可以在需要对向量执行任何操作时进入锁。例如:
type
TMyThread = class(TThread)
private
FLock: TCriticalSection;
protected
procedure Execute; override;
public
constructor Create; reintroduce;
destructor Destroy; override;
procedure Lock;
procedure Unlock;
end;
constructor TMyThread.Create;
begin
inherited Create(False);
FLock := TCriticalSection.Create;
end;
destructor TMyThread.Destroy;
begin
FLock.Free;
end;
procedure TMyThread.Lock;
begin
FLock.Enter;
end;
procedure TMyThread.Unlock;
begin
FLock.Leave;
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
Lock;
try
// do something...
finally
Unlock;
end;
end;
end;
type
TMyThread = class(TThread)
private
FPauseEvent: TEvent;
FPausedEvent: TEvent;
FResumeEvent: TEvent;
procedure CheckForPause;
protected
procedure Execute; override;
public
constructor Create; reintroduce;
destructor Destroy; override;
procedure Pause;
procedure Unpause;
end;
constructor TMyThread.Create;
begin
inherited Create(False);
FPauseEvent := TEvent.Create(nil, True, False, '');
FPausedEvent := TEvent.Create(nil, True, False, '');
FResumeEvent := TEvent.Create(nil, True, True, '');
end;
destructor TMyThread.Destroy;
begin
FPauseEvent.Free;
FPausedEvent.Free;
FResumeEvent.Free;
end;
procedure TMyThread.Pause;
begin
FResumeEvent.ResetEvent;
FPauseEvent.SetEvent;
FPausedEvent.WaitFor(Infinite);
end;
procedure TMyThread.Unpause;
begin
FPauseEvent.ResetEvent;
FResumeEvent.SetEvent;
end;
procedure TMyThread.CheckForPause;
begin
if FPauseEvent.WaitFor(0) = wrSignaled then
begin
FPausedEvent.SetEvent;
FResumeEvent.WaitFor(Infinite);
FPausedEvent.ResetEvent;
end;
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
CheckForPause;
if Terminated then Exit;
// do something...
end;
end;
如果发现工作线程比主线程更多地访问向量,则可以考虑使用A或A代替.< /P> 或者,您可以使用一些对象向工作线程发出暂停和恢复的信号。然后,主线程可以向线程发出暂停信号并等待它真正暂停,然后访问向量并在完成后取消暂停线程。例如:
type
TMyThread = class(TThread)
private
FLock: TCriticalSection;
protected
procedure Execute; override;
public
constructor Create; reintroduce;
destructor Destroy; override;
procedure Lock;
procedure Unlock;
end;
constructor TMyThread.Create;
begin
inherited Create(False);
FLock := TCriticalSection.Create;
end;
destructor TMyThread.Destroy;
begin
FLock.Free;
end;
procedure TMyThread.Lock;
begin
FLock.Enter;
end;
procedure TMyThread.Unlock;
begin
FLock.Leave;
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
Lock;
try
// do something...
finally
Unlock;
end;
end;
end;
type
TMyThread = class(TThread)
private
FPauseEvent: TEvent;
FPausedEvent: TEvent;
FResumeEvent: TEvent;
procedure CheckForPause;
protected
procedure Execute; override;
public
constructor Create; reintroduce;
destructor Destroy; override;
procedure Pause;
procedure Unpause;
end;
constructor TMyThread.Create;
begin
inherited Create(False);
FPauseEvent := TEvent.Create(nil, True, False, '');
FPausedEvent := TEvent.Create(nil, True, False, '');
FResumeEvent := TEvent.Create(nil, True, True, '');
end;
destructor TMyThread.Destroy;
begin
FPauseEvent.Free;
FPausedEvent.Free;
FResumeEvent.Free;
end;
procedure TMyThread.Pause;
begin
FResumeEvent.ResetEvent;
FPauseEvent.SetEvent;
FPausedEvent.WaitFor(Infinite);
end;
procedure TMyThread.Unpause;
begin
FPauseEvent.ResetEvent;
FResumeEvent.SetEvent;
end;
procedure TMyThread.CheckForPause;
begin
if FPauseEvent.WaitFor(0) = wrSignaled then
begin
FPausedEvent.SetEvent;
FResumeEvent.WaitFor(Infinite);
FPausedEvent.ResetEvent;
end;
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
CheckForPause;
if Terminated then Exit;
// do something...
end;
end;
下面是我的努力。它避免了雷米事件的复杂性和J.最后评论中提到的TCriticalSection的陷阱。那是假设它有效。看起来确实如此,但如果有人能帮我找到我可能掉进的陷阱,我将不胜感激 用户将看到一个TForm,其中包含一个名为VecNdx的TEdit,用户使用该TEdit输入他想要的向量值的索引,以及一个名为GetVecVal的TButton,单击该按钮时,会通过在名为VecVal的TLabel中打印VecNdx的向量值来响应 虽然向量值本身是由rand()函数生成的,但您可以将其视为单步执行查询结果集的结果,而查询结果集的大小直到最后一步之后才知道
.h file
#ifndef ThreadH
#define ThreadH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ComCtrls.hpp>
#include <vector>
#include <atomic>
//---------------------------------------------------------------------------
class TMainForm : public TForm
{
__published: // IDE-managed Components
TEdit *VecNdx; // user enters vector index
TButton *GetVecVal; // retreives value for vector at index entered above
TLabel *VecVal; // displays above value
void __fastcall GetVecValClick(TObject *Sender);
private: // User declarations
class TPopulate : public TThread
{
private:
TMainForm *Main;
void __fastcall ShowPopulated(void);
int Count;
clock_t ThreadStart; // clock() when thread starts running
protected:
void __fastcall Execute();
public:
__fastcall TPopulate(TMainForm *Parent) : Main(Parent) {}
} *Populate;
int VecSize=-1; // updated only after Populate finishes
std::vector<int> Vec;
std::atomic<int> UserNdx=-1,UserVal,CountSoFar;
public: // User declarations
__fastcall TMainForm(TComponent* Owner);
__fastcall ~TMainForm();
};
//---------------------------------------------------------------------------
extern PACKAGE TMainForm *MainForm;
//---------------------------------------------------------------------------
#endif
.cpp file
#include <vcl.h>
#pragma hdrstop
#include "Thread.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMainForm *MainForm;
//---------------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent* Owner) : TForm(Owner)
{
Populate=new TPopulate(this);
}
//---------------------------------------------------------------------------
__fastcall TMainForm::~TMainForm()
{
delete Populate;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::TPopulate::ShowPopulated(void)
{
Main->Caption = (Terminated ? String("Terminated after ") : String(Count)+" values in ")
+((clock()-ThreadStart)/CLOCKS_PER_SEC)+" secs";
Main->VecSize=Count;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::TPopulate::Execute()
{
ThreadStart=clock();
const int Mx=100000000;
Count=0;
for (int u; !Terminated && Count<Mx;)
{
Main->Vec.push_back(rand() % Mx);
Count++;
if ((u = Main->UserNdx) != -1)
{
if (Count>u) Main->UserVal=Main->Vec[u];
else Main->CountSoFar=Count;
Main->UserNdx=-1;
}
}
Synchronize(ShowPopulated);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::GetVecValClick(TObject *Sender)
{
int Ndx=VecNdx->Text.ToIntDef(-1);
if (Ndx<0 || (VecSize>=0 && Ndx>=VecSize)) throw Exception("Range Error");
if (VecSize>=0) VecVal->Caption=Vec[Ndx];
else
{
CountSoFar=0; // if Populate changes CountSoFar => Vec[UserNdx] not yet assigned
UserNdx=Ndx;
while (UserNdx!=-1); // Ensure Populate processes UserNdx
VecVal->Caption = CountSoFar ? "Populated only to "+String(CountSoFar) : int(UserVal);
}
}
//---------------------------------------------------------------------------
.h文件
#ifndef螺纹
#定义线程
//---------------------------------------------------------------------------
#包括
#包括
#包括
#包括
#包括
#包括
#包括
//---------------------------------------------------------------------------
类别:公共TForm
{
__已发布://IDE托管组件
TEdit*VecNdx;//用户输入向量索引
TButton*GetVecVal;//检索上面输入的索引处的向量值
TLabel*VecVal;//显示上述值
void uu fastcall GetVecValClick(TObject*发送方);
private://用户声明
类TPopulate:公共TThread
{
私人:
TMA*Main;
void uu快速呼叫显示填充(void);
整数计数;
clock\t ThreadStart;//线程开始运行时的clock()
受保护的:
void uu fastcall Execute();
公众:
__fastcall TPopulate(TMainForm*Parent):主(父){}
}*人口;
int VecSize=-1;//仅在填充完成后更新
std::Vec;
std::atomic UserNdx=-1,UserVal,CountSoFar;
public://用户声明
__fastcall TMainForm(t组件*所有者);
__fastcall~tmaninform();
};
//---------------------------------------------------------------------------
外部包TMainForm*main表单;
//---------------------------------------------------------------------------
#恩迪夫
.cpp文件
#包括
#布拉格语hdrstop
#包括“Thread.h”
//---------------------------------------------------------------------------
#pragma包(智能初始化)
#pragma资源“*.dfm”
TMainForm*main表单;
//---------------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent*Owner):TForm(Owner)
{
填充=新的TPopulate(本);
}
//---------------------------------------------------------------------------
__fastcall TMainForm::~TMainForm()
{
删除并填充;
}
//---------------------------------------------------------------------------
void\uu fastcall TMainForm::TPopulate::ShowPopulated(void)
{
主->标题=(终止?字符串(“终止后”):字符串(计数)+“中的值”)
+((clock()-ThreadStart)/CLOCKS_PER_secs)+“secs”;
主->向量大小=计数;
}
//---------------------------------------------------------------------------
void _fastcall TMainForm::TPopulate::Execute()
{
ThreadStart=clock();
常数int Mx=100000000;
计数=0;
对于(int u;!终止和&CountVec.push_)(rand()%Mx);
计数++;
如果((u=Main->UserNdx)!=-1)
{
如果(Count>u)Main->UserVal=Main->Vec[u];
else Main->CountSoFar=Count;
Main->UserNdx=-1;
}
}
同步(显示填充);
}
//---------------------------------------------------------------------------
void\uu fastcall TMainForm::GetVecValClick(TObject*Sender)
{
int Ndx=VecNdx->Text.ToIntDef(-1);
如果(Ndx=0&&Ndx>=VecSize))抛出异常(“范围错误”);
如果(VecSize>=0)VecVal->Caption=Vec[Ndx];
其他的
{
CountSoFar=0;//如果填充更改计数