我从来没有使用过线程,现在我试图创建一个查询线程来检查数据库状态。查询如下:如何编写和执行线程
select (*) as DBCount from v$datafile where status in 'OFFLINE';
。
该查询返回所有脱机数据库的总数。现在我想在Delphi中创建一个线程,当我运行它并将结果显示在标签上时,它将在我的应用程序的后台执行此查询。
我从来没有使用过线程,现在我试图创建一个查询线程来检查数据库状态。查询如下:如何编写和执行线程
select (*) as DBCount from v$datafile where status in 'OFFLINE';
。
该查询返回所有脱机数据库的总数。现在我想在Delphi中创建一个线程,当我运行它并将结果显示在标签上时,它将在我的应用程序的后台执行此查询。
在Delphi中有TThread
类。您可以使用Delphi IDE中的简单向导(在Turbo Delphi中:File-> New-> Delphi Projects-> Delphi Files-> Thread Obcjet)创建此类线程。在它的构造函数中创建与数据库的连接,并且在Execute
方法中你可以创建循环查询数据库,更新一些全局变量(不声明为threadvar
)并且休息一段时间。
多线程很难。使用AsyncCalls这样的简单线程框架可能会更好。
继StackOverlow线程可以给你如何解决你的问题的详细信息:
How Do I Choose Between the Various Ways to do Threading in Delphi?
Delphi thread that waits for data, processes it, then resumes waiting
这很容易使用AsyncCalls来完成。让我们假设你的非线程的代码如下所示(忽略所有的错误处理):
Query := 'select (*) as DBCount from...';
ExecuteSQL(SqlConnection,Query);
SqlResult := GetSqlResult(SqlConnection);
SqlRow := GetSqlRow(SqlResult);
MyLabel.Text := SqlRow[0];
...Go on to do other things...
其中第二行是阻塞(等待服务器回复)。新代码应该是这样的:
uses AsyncCalls; //added to your existing uses statement
...
procedure DoesSomething();
var Thread: TAsyncCall; //your interface to AsyncCalls
procedure AsyncSqlCall(); //this is a LOCAL procedure
Query := 'select (*) as DBCount from...';
ExecuteSQL(SqlConnection,Query);
SqlResult := GetSqlResult(SqlConnection);
SqlRow := GetSqlRow(SqlResult);
EnterMainThread;
try
Assert(GetCurrentThreadId = MainThreadId);
MyLabel.Text := SqlRow[0];
finally
LeaveMainThread;
end;
begin //this begins proc DoSomething()
...
Thread := LocalAsyncCall(@AsyncSqlCall);
...Go on to do other things...
end;
我们所做的就是把阻塞的SQL调用在本地proc和告诉AsyncCalls在另一个线程来执行它,而主线程继续执行。唯一棘手的部分是使用VCL,它不是线程安全的。所以我让那条线安全地在主线程中运行。
如果在某些时候,你需要确保异步线程完成后,您将执行此行阻塞主线程,直到AsyncSqlCall终止:
Thread.sync;
这里的真正好处是,AsyncCalls处理所有关于创建线程池,创建线程等等的东西。虽然在本例中没有显示,但可以将变量传递给线程,并返回一个值。您不必使用本地流程,但这样做可以访问所有本地流程。您可以将所有这一切全局化,然后在一个例程中启动Async线程,并在另一个例程中测试它的完成。
限制:
你的异步线程不能接触(读或写)什么,但它自己的变量,而异步线程运行时,你的主线程不能碰它们。你必须这样编码。没有什么会阻止你制造混乱。在上面的例子中,你的主线程不能碰到Query,SqlConnection,SqlResult和SqlRow。如果您的代码的任何部分在Thread.sync调用之前使用了其中一个变量,那么您的代码将会正常工作 - 但会在您不曾预料的奇怪地方抛出异常。所以保持简单。
您的异步线程不得使用VCL。上面的示例显示了几种安全解决此限制的方法之一。
最后:
AsyncCalls不是一个完整的多线程框架。这只是一种异步调用函数的方式(即不需要等待)。不要试图把它推得太远 - 我的意思是,不要试图把它作为完全多任务程序的基础。
我删除了pthread标签,因为它与delphi标签不兼容。 – mghie 2010-09-27 07:04:11