【问题标题】:how to write and execute a thread如何编写和执行线程
【发布时间】:2011-04-17 14:56:25
【问题描述】:

我以前从未使用过线程,现在我正在尝试创建一个带有查询的线程来检查数据库状态。查询如下:

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

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

【问题讨论】:

  • 我删除了 pthread 标签,因为它与 delphi 标签并不真正兼容。

标签: multithreading 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,它不是线程安全的。所以我让那行安全地在主线程中运行。

如果在某些时候您需要确保 Async 线程已完成,您将执行此行以阻塞主线程,直到 AsyncSqlCall 终止:

Thread.sync; 

这里真正的好处是 AsyncCalls 处理所有关于创建线程池、创建线程等的事情。虽然在这个例子中没有显示,你可以将变量传递给你的线程,并返回一个值。您不必使用本地 proc,但这样做可以访问所有本地变量。您可以将所有这些设为全局,然后在一个例程中启动 Async 线程,并在另一个例程中测试其是否完成。

限制:

您的异步线程不得接触(读取或写入)除其自身变量之外的任何内容,并且您的主线程不得在异步线程运行时接触它们。你必须这样编码。没有什么能阻止你制造完全的混乱。在上面的例子中,你的主线程不能接触 Query、SqlConnection、SqlResult 和 SqlRow。如果您的代码的任何部分在调用 Thread.sync 之前使用了这些变量之一,那么您的代码将可以工作——但会在您从未预料到的奇怪地方抛出异常。所以保持简单。

您的异步线程不得使用 VCL。上面的示例显示了安全绕过此限制的几种方法之一。

最后:

AsyncCalls 不是一个完整的多线程框架。这只是一种异步调用过程和函数的方式(即无需等待)。不要试图把它推得太远——我的意思是,不要试图让它成为一个完全多任务程序的基础。

【讨论】:

    【解决方案2】:

    在这里您可以找到有关在数据库上使用线程的讨论。

    Simple Thread Sample Delphi

    有些代码对你有用。

    问候。

    【讨论】:

      【解决方案3】:

      多线程很难。使用 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

      【讨论】:

      • 另一个不错的线程框架是 gabr 的 OmniThreadLibrary :P otl.17slon.com
      【解决方案4】:

      在 Delphi 中有 TThread 类。您可以使用 Delphi IDE 中的简单向导创建这样的线程(在 Turbo Delphi 中:文件->新建->Delphi 项目->Delphi 文件->线程 Obcjet)。在其构造函数中创建与数据库的连接,在Execute 方法中,您可以创建查询数据库的循环,更新一些全局变量(未声明为threadvar)并休眠一段时间。

      【讨论】:

      • 将结果放入threadvar 将使任何其他线程无法获得结果。这有什么用?
      • upps,对不起,我的错,当然这应该是正常变量。
      • 只是想知道为什么这个答案被否决(尽管有 threadvar),因为我认为它很有帮助,并为 OP 提供了一个开始和开始阅读的地方。如果 SO 只允许有动机的投反对票,那就太好了……
      • @Remko:我没有投反对票,但它仍然比有用的问题更多 - 混合线程上下文(“在其构造函数中创建与数据库的连接,并在 Execute 方法中创建循环该查询数据库”)在没有必要的地方只是不是一个好建议。
      猜你喜欢
      • 1970-01-01
      • 2013-07-27
      • 2020-05-29
      • 1970-01-01
      • 1970-01-01
      • 2011-07-24
      • 1970-01-01
      • 1970-01-01
      • 2021-07-18
      相关资源
      最近更新 更多