在 TThread.Execute 中调用 TDataModule 方法
一般来说,在 TThread.Execute 过程中是否可能 调用 TDataModule 方法,其中不涉及视觉活动?
谢谢大家,马西莫。
In general, is it possible in a TThread.Execute procedure
to call a TDataModule method, in which there is no visual activity involved?
Thanks to all, Massimo.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
最简单的方法是使用 TThread.Synchronize 调用数据模块中的方法。
但是,如果您不希望这样做,即使不涉及任何视觉活动,您也应该确定是否需要添加 关键部分来保护您。
对任何标准或第三方 VCL 组件的任何访问,无论是可视的(TButton)还是非可视的(数据集)都应被视为不安全。对本地数据对象(如私有字段或全局变量)的任何访问也必须受到临界区的保护。
这是从后台线程到数据模块的直接调用:
这是数据模块中的代码,我向您展示了一段示例代码,以确保我们是现在唯一接触 FList 的线程
: Delphi 多线程编程,简而言之就是:
The easiest way to go is to use TThread.Synchronize to invoke a method in your data module.
However, if you do not wish to do that, even when no visual activity is involved, you should determine whether or not you need to add a critical section to protect you.
Any access to any standard or third-party VCL component, whether it is visual (TButton) or non-visual (datasets) should be considered UNSAFE. Any access to a local data object (like a private field or global variable) must also be protected by critical sections.
Here's a direct call from a from background thread to your data module:
Here's the code in your data module, which I am showing you a sample bit of code that makes sure that we are the only thread touching FList right now:
Some starter rules for Delphi multi-threaded programming, in a nutshell are:
简短回答:是
详细回答:Windows 的问题是所有 GUI 活动都应该在单个线程中完成。 (嗯,上面的陈述可以扩展、修改、增强等,但对于我们的讨论来说就足够了)。因此,如果您确定 TDataModule 方法中不涉及任何“GUI 事物”(请注意,这甚至可能是
ShowMessage
调用),那么请继续。更新:当然,有一些技术可以从辅助线程更新 GUI,但这意味着某种准备(消息传递、同步等)。这不是很难,只是你不能“盲目地”从另一个线程调用改变 GUI 的方法。
Short answer: yes
Long answer: The problem with Windows is that all the GUI activity should be done in a single thread. (Well, the above statement can be expanded, amended, enhanced etc. but for our discussion is enough). So, if you are sure that in your TDataModule method there isn't any 'GUI thing' involved (beware, this can be even a
ShowMessage
call) then go ahead.UPDATE: Of course, there are techniques to update your GUI from a secondary thread, but this implies some sort of preparation (message passing,
Synchronize
etc.). Isn't something very hard, just that you cannot 'blindly' call from another thread a method who changes the GUI.当被问及任何问题时,要使用我们行业最喜欢的答案:这取决于。
如果您的数据模块上有一个完全独立的方法(即可以是静态方法),那么您应该不会有任何问题。
示例
另一方面,如果该方法使用任何全局状态,则从多个线程调用它时可能会遇到麻烦。
示例
全局状态应该被解释得非常广泛。 TQuery、TTable、刷新 GUI、使用任何全局变量……都是全局状态,并且不是线程安全的。
To use our industries favorite answer when asked anything: It depends.
If you have a method on your datamodule that is completely self contained (ie could be a static method), you shouldn't have any problem.
Example
If on the other hand, the method uses any global state, you might get into trouble when calling it from multiple threads.
Example
Global state should be interpreted very wide. A TQuery, a TTable, refreshing the GUI, using any global variable, ... is all global state and isn't thread safe.
是的,我的问题很模糊。
我的程序是一个图形统计应用程序,它必须通过TChart显示甘特图,描述一台或多台机床的状态、警报或加工订单。
在主管 PC 上的服务器(配备 TIdTcpServer 和一些 DB 组件)
正在局域网上监听我的应用程序。
主窗体客户端允许最终用户选择日期范围(期间)和
查询服务器的单位(机器)。之后,用户按下一个按钮(有
3 功能):创建一个新表单(和数据模块)来显示结果。
收集数据的工作由线程完成,因为:
1)它可能是一项很长的工作,因此可能会冻结 GUI;
2) 用户可以启动多个表单来查看各种结果。
我有一个基本的数据模块(带有一个带有多个收集数据功能的 TIdTcpClient),
一个基本形式(从未实例化,具有许多所有数据形式所共有的特征,以及工作线程的定义)。
此外,使用 VFI,我还有两个单元:
因此,当最终用户按下按钮时,一个新表单及其自己的数据模块和
线程被创建;线程通过 ExecuteInThread 使用自己的数据模块
功能。数据准备好后,将向表单发送一条 PostMessage,该表单会更新
图表。
Yes, my question is very vague.
My program is a graphical statistics app, it has to display Gantt chart, by means of TChart, describing the states, alarms or machined orders of one or more Tool Machine.
On the supervisor PC a server (equipped with a TIdTcpServer and some DB components)
is listening to my app on the LAN.
The main-form client allows the final user to choice a range of dates (period) and
the units (machines) to query the server. After that, the user press a button (there are
3 functionalities): a new form (and Datamodule) is created to display the results.
The work of collecting data is completed by a thread because:
1) it can be a long job so it could freeze the GUI;
2) the user can launch more than one form to see various results.
I have a basic Datamodule (with a TIdTcpClient with several function to collect the data),
a basic form (never instantiated, with a lot of characteristics common to all data form, and the definition of the worker thread).
Furthermore, using VFI, I also have two units:
So, when the final user presses the button, a new form and its own datamodule and
thread are created; the thread uses its own datamodule by means of ExecuteInThread
function. When data are ready, a PostMessage is sent to the form, which updates
the chart.
正如利文所写,这取决于情况。
如果数据模块上有数据库组件,则必须知道它们是否是线程安全的,或者使它们成为线程安全的。
某些数据库组件需要每个线程有一个单独的会话对象。
Like Lieven writes, it depends.
If you have database components on the datamodule, you have to know if the are thread safe, or to make them threadsafe.
Some database components require a seperate session object per thread.
在线程中使用数据模块时存在问题:
如果您在窗体的 OnDestroy 事件中终止线程并等待它 (WaitFor) - 您将遇到死锁。
主 UI 线程设置锁定
,您的线程将在其数据模块析构函数中无限等待,因此
,如果您想在关闭 MainForm 时等待线程,请在 OnClose 事件或项目的主文件中执行操作,
或者您可以在 Synchronize 中销毁它
There is a problem where you work with datamodule in Thread:
If you terminate your thread in OnDestroy event of form and are waiting for it (WaitFor) - you'll have a deadlock.
Main UI thread set lock
and your thread will wait infinitely in it's datamodule destructor with the same
So, if you want to wait for your threads when close MainForm, do it in OnClose event or in Project's main file
Or you can destroy it in Synchronize