2010-09-27 40 views
6

我从来没有使用过线程,现在我试图创建一个查询线程来检查数据库状态。查询如下:如何编写和执行线程

select (*) as DBCount from v$datafile where status in 'OFFLINE';

该查询返回所有脱机数据库的总数。现在我想在Delphi中创建一个线程,当我运行它并将结果显示在标签上时,它将在我的应用程序的后台执行此查询。

+0

我删除了pthread标签,因为它与delphi标签不兼容。 – mghie 2010-09-27 07:04:11

回答

0

在Delphi中有TThread类。您可以使用Delphi IDE中的简单向导(在Turbo Delphi中:File-> New-> Delphi Projects-> Delphi Files-> Thread Obcjet)创建此类线程。在它的构造函数中创建与数据库的连接,并且在Execute方法中你可以创建循环查询数据库,更新一些全局变量(不声明为threadvar)并且休息一段时间。

+2

将结果放入一个'threadvar'将使任何其他线程无法得到结果。那会如何有用? – mghie 2010-09-27 07:02:15

+1

upps,抱歉,我的错误,当然这应该是正常变量。 – 2010-09-27 07:37:37

+0

只是想知道为什么这个答案是downvoted(即使threadvar),因为我认为这是有益的,并给OP一个地方开始并开始阅读。如果SO只允许动机downvote ... – Remko 2010-09-27 12:04:50

7

多线程很难。使用AsyncCalls这样的简单线程框架可能会更好。

继StackOverlow线程可以给你如何解决你的问题的详细信息:

Delphi - Threading frameworks

How Do I Choose Between the Various Ways to do Threading in Delphi?

Delphi thread that waits for data, processes it, then resumes waiting

+0

另一个不错的线程框架是gabr的OmniThreadLibrary:P http://otl.17slon.com/ – Remko 2010-09-27 12:02:20

+0

@Remko:它包含在我指的线程中。 – gabr 2010-09-27 12:55:47

0

在这里你可以找到一个关于使用数据库线程的讨论。

Simple Thread Sample Delphi

有一些代码,可能是有用的为您服务。

问候。

1

这很容易使用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不是一个完整的多线程框架。这只是一种异步调用函数的方式(即不需要等待)。不要试图把它推得太远 - 我的意思是,不要试图把它作为完全多任务程序的基础。