tcl多线程编程的使用说明

合集下载

TCL编程高级教程讲解

TCL编程高级教程讲解
➢ 缺点:不支持版本号,不便于脚本库的更新和维护。由 于脚本库只能用TCL语言编写,能够实现的功能有限。 另外,每个脚本库的路径都要添加到 auto_path 变量中 也比较烦琐。
为解决上述问题和进一步提高TCL 的扩展能力,较新版 本的TCL提供了更好的程序包机制。
脚本库和程序包
• 程序包
Q:什么是程序包? A:由于脚本库的局限性,TCL提供了更好的
TCL已经有一个这样的集合,就是我们指的 全局命名空间。全局命名空间将所有的全局变量 和命令放在一起。 命名空间也叫做名称空间、名 称域、命名域 等。
命名空间
• 命名空间创建:
用 namespace eval 命令创建一个新的命名空间
• 命名空间查询
如果要在命名空间XXX之外查询命名空间内部变 量的值xxx,可以用如下语句: set :: XXX::xxx
命名空间
• 输入命令和输出命令
命名空间常常用来描述库,需要频繁使用命名空间前缀, 用输入命令和输出命令可以省略命令前面的命名空间前缀。
输入命令: namespace import 输出命令: namespace export
命名空间
• 输入命令
➢ namespace import 命令只输入命名空间中用namespace export命令输 出的命令
package 机制来实现对TCL的共用和扩展,也就 是程序包 。
脚本库和程序包
• 创建TCL程序包:
把你想包含在某个包中的所有自定义过程 放到一个TCL脚本文件中,然后在文件的开头 使用 package provide 命令指明这个包的名字和 版本即可。
脚本库和程序包
– 如果一个函数在几个脚本库中都有定义的话,TCL会按照搜索顺序自动加 载在 auto_path 中位置靠前的那个库。因此,如果加载的脚本库要先被搜 索的话,可以使用 linsert 命令将其插入到 auto_path 中靠前的位置中, 例如: % set auto_path [linsert $auto_path 0 c:/tcllib/lib1]

2024版TCL教程(中文)

2024版TCL教程(中文)
《TCL/TK入门经典》
这是一本经典的TCL/TK入门书籍,详细介绍了TCL语言的基础知识和常用命令,以及如何使 用TCL/TK进行GUI编程。
《TCL编程之道》
这本书深入探讨了TCL编程的高级技巧和最佳实践,适合有一定TCL基础的读者。
TCL博客
一些专注于TCL技术的博客也是学习的好资源,如"TCL专家博客"、"TCL技术分享"等,这些 博客通常会分享一些实用的技巧和经验。
MySQL、PostgreSQL、SQLite等, 并提供连接示例代码。
连接数据库
介绍如何在TCL中执行SQL语句, 包括查询、插入、更新和删除等操 作,并提供相应的示例代码。
执行SQL语句
讲解如何处理查询结果集,包括遍 历结果集、获取字段值和元数据等 操作,并提供相应的示例代码。
TCL实例分析
05
THANKS.
数据遍历
通过`foreach`命令遍历数组或列表中的每个元素,并对每个元 素执行相应的操作。
文件操作与I/O流
文件读写
TCL提供了文件读写命令,如`open`、`read`、`write`等,用于实 现文件的读写操作。
文件路径处理
TCL支持文件路径的处理,如路径拼接、路径分解等,方便进行文 件操作。
错误处理
TCL提供了错误处理机制,如使用`catch`命令捕获异常并处理。通过错误处理,可以确 保程序的稳定性和可靠性。
TCL高级特性
03
过程与函数
过程定义
01
TCL支持自定义过程,可以通过`proc`关键字定义过程,并指定
过程名和参数列表。
函数调用
02
通过过程名及参数列表调用已定义的过程,实现代码复用和模

tcl define_proc用法

tcl define_proc用法

tcl define_proc用法
在Tcl中,`define`不是一个内置的关键字,而是使用命令定义过程的语言。

其中,`proc`命令用于定义一个过程,该过程可以被其他程序或脚本调用。

`proc`命令有多种参数,其中包括过程的名称、输入参数和过程体。

例如,可以使用以下代码定义一个名为"hello"的过程:
```tcl
proc hello {} {puts "Hello, Tcl! "}
```
然后,可以使用"hello"命令调用该过程,以便在命令行中打印出"Hello, Tcl! "。

通过定义和调用多个过程,可以组织Tcl脚本并实现所需的功能,从而编写模块化、可重用的代码。

此外,`define_proc`是Tcl过程定义的一种形式,允许在过程定义中设置一些属性。

这些属性可以包括过程的名称、参数、返回类型和其他信息。

通过使用`define_proc`,可以更精确地控制过程的行为和功能。

tcl 语法 除法

tcl 语法 除法

tcl 语法除法TCL语法-除法在TCL(Tool Command Language)编程语言中,除法操作是常见且必要的运算之一。

TCL提供了多种方法来执行除法运算,以满足不同的需求。

本文将介绍TCL语法中除法运算的不同形式及其用法。

1. 除法操作符在TCL中,除法可以使用“/”操作符进行计算。

例如,使用以下命令执行整数除法:```set result [expr 10 / 3]```这将返回3,因为10除以3等于3.333,但这是整数除法,结果会被截断为最接近的整数值。

2. 浮点除法要执行浮点除法,可以使用“double”函数将操作数转换为浮点数。

例如:```set result [expr double(10) / double(3)]```这将返回3.3333333333333335作为双精度浮点数。

在此示例中,使用double 函数将整数10和3转换为浮点数进行相除。

3. 向下取整除法有时候我们需要将除法结果向下取整,TCL提供了“floor”函数来满足这个需求。

例如:```set result [expr {floor(10.0 / 3.0)}]```这将返回3.0作为结果。

在这个例子中,我们使用了floor函数将浮点除法的结果向下取整。

4. 取余操作除了整数除法,TCL还提供了取余操作符“%”,用于计算除法的余数。

例如,以下命令计算10除以3的余数:```set remainder [expr 10 % 3]```这将返回1,因为10除以3的商为3,余数为1。

5. 除法的应用场景除法在计算中有广泛的应用场景。

例如,在分配任务给工人时,可以使用除法来确定每个工人应该完成的任务数量。

另一个例子是计算平均值,可以使用除法将总和除以计数来得到平均值。

6. 除法的注意事项在进行除法运算时,需要注意一些细节。

首先,除数不应为零,因为除以零是无效的并且会导致错误。

其次,如果希望获得精确的小数结果,则需要将操作数转换为浮点数。

Tcl用法详述

Tcl用法详述

Tcl用法详述T C L用法祥述一TCL语法1 脚本、命令和单词符号一个TCL脚本可以包含一个或多个命令。

命令之间必须用换行符或分号隔开,下面的两个脚本都是合法的:set a 1set b 2或set a 1;set b 2TCL的每一个命令包含一个或几个单词,第一个单词代表命令名,另外的单词则是这个命令的参数,单词之间必须用空格或TAB键隔开。

TCL解释器对一个命令的求值过程分为两部分:分析和执行。

在分析阶段,TCL 解释器运用规则把命令分成一个个独立的单词,同时进行必要的置换(substitution);在执行阶段,TCL 解释器会把第一个单词当作命令名,并查看这个命令是否有定义,如果有定义就激活这个命令对应的C/C++过程,并把所有的单词作为参数传递给该命令过程,让命令过程进行处理。

2 置换(substitution)注:在下面的所有章节的例子中,'%'为TCL的命令提示符,输入命令回车后,TCL会在接着的一行输出命令执行结果。

'//'后面是我自己加上的说明,不是例子的一部分。

TCL解释器在分析命令时,把所有的命令参数都当作字符串看待,例如:%set x 10 //定义变量x,并把x的值赋为1010%set y x+100 //y的值是x+100,而不是我们期望的110x+100上例的第二个命令中,x被看作字符串x+100的一部分,如果我们想使用x的值'10' ,就必须告诉TCL解释器:我们在这里期望的是变量x的值,而非字符'x'。

怎么告诉TCL解释器呢,这就要用到TCL 语言中提供的置换功能。

TCL提供三种形式的置换:变量置换、命令置换和反斜杠置换。

每种置换都会导致一个或多个单词本身被其他的值所代替。

置换可以发生在包括命令名在内的每一个单词中,而且置换可以嵌套。

1) 变量置换(variable subtitution)变量置换由一个$符号标记,变量置换会导致变量的值插入一个单词中。

Tcl编程教程

Tcl编程教程

Tcl编程教程第一部分:基础知识```tclputs "Hello, Tcl!"```将文件保存为`hello.tcl`。

在命令行中,使用以下命令运行这个程序:```bashtclsh hello.tcl```你将看到输出`Hello, Tcl!`。

3. 变量:在Tcl中,你可以使用`set`命令创建变量。

例如:```tclset name "John"puts $name```输出将会是 `John`。

4. 字符串操作:Tcl提供了许多可以操作字符串的内置命令。

例如,你可以使用`string length`命令来获取字符串的长度:```tclset str "Hello, World!"set len [string length $str]puts "String length: $len"```输出将会是 `String length: 13`。

5. 数字操作:除了操作字符串,Tcl还支持对数字的操作。

你可以使用`expr`命令来进行数学运算:```tclset num1 10set num2 5set sum [expr $num1 + $num2]puts "Sum: $sum"```输出将会是 `Sum: 15`。

第二部分:条件和循环1. 条件语句:在Tcl中,你可以使用`if`语句来进行条件判断。

例如:```tclset num 10if {$num > 0}puts "Positive"} elseif {$num < 0}puts "Negative"} elseputs "Zero"```输出将会是 `Positive`。

2. 循环语句:Tcl中有两种常见的循环语句,`while`循环和`foreach`循环。

tcl中isshare用法_概述及解释说明

tcl中isshare用法_概述及解释说明

tcl中isshare用法概述及解释说明1. 引言1.1 概述本篇长文将详细介绍Tcl中isshare命令的用法,并对其进行解释说明。

在Tcl 编程中,isshare是一个非常重要的命令,它能够检测给定的变量是否是共享变量。

共享变量在并发编程中起到关键作用,因此了解isshare的使用方法以及它与其他Tcl命令的关系对于正确实现并发编程和优化性能至关重要。

1.2 文章结构本文将按照以下结构进行介绍和解释:- 引言部分将提供概述,并明确文章的目的和结构。

- 接下来,我们将深入解释isshare命令的定义、功能以及具体使用方法。

- 我们还将探讨isshare与其他Tcl命令之间的联系和互动方式。

- 在示例和应用场景分析部分,我们将通过示例代码介绍isshare在实际应用中的具体情况,并进行深入解析。

- 同时,在并发编程方面,我们将分析isshare在该领域中的应用场景,并评估它对性能和资源消耗的影响。

- 为了帮助读者避免常见误用和错误排查问题,在常见问题及解决方法部分,我们提供了常见误用和错误排查的指南,并对可能遇到的问题进行解答与说明。

- 此外,我们还将分享最佳实践和优化建议,以便读者能够更好地使用isshare命令。

- 最后,在结论与展望部分,我们对本文的主要观点和发现进行总结,并探讨了Tcl中isshare用法的未来发展趋势。

1.3 目的本文旨在提供关于Tcl中isshare命令用法的详尽说明。

通过全面介绍isshare 命令的定义、功能、使用方法以及与其他Tcl命令的关系,读者将能够全面理解isshare在编程中的重要性和应用场景。

此外,示例代码和应用场景分析将帮助读者更好地理解如何正确使用isshare,同时评估其对性能和资源消耗的影响。

常见问题及解决方法部分提供了避免误用和排查问题时的指南,有助于读者更快地解决潜在问题。

最后,在结论与展望部分,本文将总结主要观点并探讨Tcl中isshare用法未来发展趋势,为读者提供进一步思考和研究方向。

tcl中expect用法

tcl中expect用法

在Tcl(Tool Command Language)中,expect是一个用于自动化交互式程序的工具。

它允许你编写脚本,以模拟用户与另一个程序的交互。

expect可以等待特定的输出模式出现,并根据这些模式作出响应。

下面是expect在Tcl中的基本用法:安装和导入Expect包:首先,确保你的Tcl环境中已经安装了Expect包。

你可以使用package require Expect来导入它。

创建spawn进程:使用spawn命令启动一个外部程序。

例如,spawn ssh user@host会启动一个SSH会话。

使用expect等待模式:使用expect命令等待特定的输出模式。

你可以等待多个模式,并为每个模式定义一个响应。

发送响应:一旦expect匹配到一个模式,你可以使用send命令发送响应。

关闭spawn进程:使用expect eof等待进程结束,或者使用close命令关闭spawn进程。

下面是一个简单的Tcl脚本示例,演示如何使用Expect自动登录到一个SSH服务器:tcl#!/usr/bin/tclsh# 导入Expect包package require Expect# 启动SSH会话spawn ssh user@host# 等待密码提示并发送密码expect "password:"send "your_password\r"# 等待命令提示符并发送命令expect "$ "send "ls\r"# 等待命令执行完成并打印输出expect "$ "puts $expect_out(buffer)# 关闭spawn进程closeexit 0注意:在实际使用中,为了安全起见,不建议在脚本中硬编码密码。

你可以考虑使用SSH密钥认证等更安全的方式。

此外,确保在使用Expect时遵循最佳实践,以避免潜在的安全风险。

TCL教程

TCL教程

↖(^ω^)↗↖(^ω^)↗查看文章TCL语言的一些学习资料TCL语言Tcl tick 的构成-------Tcl是一种很通用的脚本语言,它几乎在所有的平台上都可以解释运行,功能强大。

是tool command language的缩写,发音为"tickle”,实际上包含了两个部分:一个语言和一个库。

首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。

它有一个简单的语法和很强可扩充性,Tcl可以创建新的过程以增强其内建命令的能力。

其次,Tcl是一个库包,可以被嵌入应用程序,Tcl的库包含了一个分析器、用于执行内建命令的例程和可以使你扩充(定义新的过程)的库函数。

应用程序可以产生Tcl命令并执行,命令可以由用户产生,也可以从用户接口的一个输入中读取(按钮或菜单等)。

但Tcl库收到命令后将它分解并执行内建的命令,经常会产生递归的调用。

在下面的清单中,将会发现第一个很常见的示例程序,它是用Tcl 实现的。

这是一个完整的脚本:第一行命令调用tclsh 环境,第二行命令执行实际工作。

用您所选择的文本编辑器创建该脚本,输入chmod +x hello.tcl 使之成为可执行文件,然后执行它以测试您这件“作品”。

~/tcltk$ cat hello.tcl#!/usr/bin/tclshputs stdout {Hello, World!}~/tcltk$ ./hello.tclHello, World!Tcl 和Tk 是解释型的、可扩展脚本语言。

与BSD 许可证十分相似,该许可证允许在任何情况下自由使用该软件,只要在所有副本中保留该版权并且在任何分发中一字不差地传递通告。

这个许可证条款使Tcl/Tk 成为自由软件。

Tcl/Tk 是一种解释型环境。

可以通过添加预编译的C 函数来扩展Tcl 解释器,可从Tcl 环境内部调用Tcl 解释器。

可以为特定目的或一般的以及广泛使用的而定制这些扩展。

TCL中文教程范文

TCL中文教程范文

TCL中文教程范文一、TCL简介TCL是一种解释性的脚本语言,由John Ousterhout于1988年开发。

它被设计用于与其他软件组件进行交互,并提供了强大的编程和脚本功能。

TCL提供了丰富的内置函数和命令,可以用于控制流、字符串处理、文件操作等。

二、TCL语法1.注释在TCL中,使用“#”符号来表示注释。

一行以“#”开头的内容将被视为注释,不会被执行。

2.变量TCL中的变量无需声明即可使用。

您可以使用“set”命令来定义变量,如下所示:```set variable value```例如,要定义一个名为“name”的变量,可以使用以下命令:```set name "John"```类似地,您可以使用“$”符号来使用变量的值,如下所示:```puts $name```3.控制流TCL提供了多种控制流语句,如条件语句(if)、循环语句(while、for)、分支语句(switch)等。

以下是几个示例:-条件语句:```if {$x > $y}puts "x is greater than y"} elseif {$x == $y}puts "x is equal to y"} elseputs "x is less than y"```-循环语句:```set i 0while {$i < 10}puts $iincr ifor {set i 0} {$i < 10} {incr i}puts $i```-分支语句:```switch $option"a"puts "Option a selected"}"b"puts "Option b selected"}defaultputs "Invalid option"}```4.字符串处理TCL提供了丰富的字符串处理功能,如连接字符串、截取字符串、查找子字符串等。

TCL-TK编程实践

TCL-TK编程实践

第3部分 TK基础23TK基本原理23.1TK中的Hello,World!我们的第一个Tk脚本非常简单。

它创建了一个按钮,当你点击它时,就向标准输出设备打印“Hello,World!”。

在按钮控件上方是一个由窗口管理器提供的标题栏,本例中在X视窗系统中是twm。

23.1.1例23-1 “Hello,World!”Tk程序第一行标识了脚本的解释器:如果此脚本象其它NUIX命令文件那样被调用,则这个特殊的行是必要的,第2节描述了如何设置脚本于不同的平台上。

在这个脚本中有两个TCL命令:一个用来创建按钮,一个用来使其在显示上可见。

bu tton命令创建一个按钮的实例:按钮的名字是.hello。

按钮上的标签是Hello,与此按钮相关联的命令是:pack命令将按钮映射到屏幕上。

并提供了一些堆叠参数,所以在按钮周围有空间。

当你将这两个命令键入wish中时,当button命令给出时,你不会看到任何东西。

然而,在pack命令之后,你将会看到空的主窗口将会收缩到足以容纳按钮和其添充空隙(padd ing)。

包装器的行为在第24和第25章进行深入的讨论。

Tk使用一种基本对象的系统来创建和命令控件。

与每一种小控件(如按钮)相关联的是一个用于创建此种类别控件实例的命令。

当小控件被创建时,一个作用在这个控件实例上的一个新的TCL命令就定义了。

例23-1创建了一个名为.hello的按钮,并且我们可以使用其名字作为一个TCL命令来操纵此按钮。

例如,我们可以使用此按钮高亮几次:或者,我们可以运行与此按钮相关联的命令:Tk有控件类和实例,但是它并不是完全面向对象的。

不可能去对一个控件类派生子类并继承。

相反,Tk,提供了非常灵活的控件,可以通过多种方式调节其外观。

资源数据库可以存储被许多控件共享的配置信息,并且新的类也可以被引入到组资源中。

控件行为通过使用分缓绑定的绑定标签得到共享。

Tk使用部件(composition)来组装共享行为和属性的控件。

tcl教程

tcl教程

tcl教程TCL(工具命令语言)是一种脚本语言,主要用于实现自动化工作流程、快速开发小型工具和控制系统等应用。

它具有简单易学、功能丰富以及可移植性好等特点。

本教程将带你从基础开始逐步学习TCL的语法和常用命令,并通过实例演示帮助你快速掌握TCL编程。

1. TCL的安装和运行环境配置首先,你需要下载并安装TCL的最新版本。

在安装过程中,请根据操作系统选择正确的安装文件,并按照向导进行安装。

安装完成后,你可以在命令行界面中输入"tclsh"来启动TCL解释器,并进入TCL编程环境。

2. TCL脚本的基本结构和语法一个TCL脚本通常由一系列的命令组成,每条命令占据一行。

TCL命令以"$"符号开头,如"$command argument1 argument2"。

TCL的注释以"#"符号开头,后面的内容将被忽略。

以下是一个简单的TCL脚本示例:```tcl#!/usr/bin/tclsh# 输出Hello World!puts "Hello World!"```3. 变量和数据类型TCL支持多种数据类型,包括整数、浮点数、字符串、列表和字典等。

你可以使用"set"命令定义一个变量,并使用"$"符号在其他地方引用该变量。

以下是一些例子:```tclset name "Tom"set age 18set pi 3.14159set fruits {apple banana orange}set person(name) "John"```4. 控制流结构TCL提供了常见的控制流结构,如条件语句和循环语句,用于控制程序的执行流程。

以下是一些控制流语句的示例:if语句:```tclif {$age >= 18} {puts "成年人"} else {puts "未成年人"}```while循环语句:```tclset num 1while {$num <= 10} {puts $numincr num}```5. 文件操作TCL提供了一组用于文件操作的命令,如打开文件、读取文件、写入文件和关闭文件等。

《tcl入门培训》课件

《tcl入门培训》课件

正则表达式
了解正则表达式的语法和使用,以及在TCL中 如何应用。
文件和目录操作
学习如何在TCL中进行文件和目录的读写操作。
网络编程
掌握在TCL中进行网络编程的基本方法。
多线程编程
了解如何在TCL中使用多线程实现并发编程。
第四部分:TCL与其他语言的结合
本部分将介绍TCL与其他编程语言的结合,包括TCL和C语言、TCL和Python、TCL和Perl的结合,并 通过演示案例展示它们的应用。
了解如何使用TCL与数据库进行交互,实现 数据的存储和检索。
TCL应用开发案例分析
通过实际案例分析,展示TCL在应用开发中 的优势和实际应用场景。
第六部分:TCL最佳实践
本部分将介绍TCL编程的最佳实践,包括编程规范、代码调试技巧、性能优化技巧以及最佳实践案例分 享。
1 TCL编程规范
学习编写清晰、可维护的TCL代码的规范 和风格。
第五部分:TCL应用开发
本部分将介绍TCL的应用开发,包括GUI应用开发、WEB应用开发和数据库应用开发,并通过案例分析 展示其实际应用。
TCL的GUI应用开发
学习如何使用TCL开发图形界面应用程序。
TCL的WEB应用开发
掌握如何使用TCL开发WEB应用程序,构建 动态网页。
TCL的数据库应用开发
2 TCL代码调试技巧
掌握TCL代码的调试方法,以快速定位问 题并进行修复。
3 TCL性能优化技巧
了解如何优化TCL代码的性能,提升程序 执行效率。
4 TCL最佳实践案例分享
通过实际案例分享,了解TCL在不同场景 下的最佳实践。
结束语
TCL是一门强大而灵活的脚本语言,在不同领域都有广泛的应用。本课程提供了TCL的全面介绍 和学习资源推荐,希望能够帮助你深入掌握TCL编程。

tcl_tk编程,tcl_tk编程教程

tcl_tk编程,tcl_tk编程教程

Tcl / Tk 大全 (1)一. Tcl / Tk简介 (1)1.1 背景 (1)1.2 定义 (2)二. Tcl / Tk基础 (2)2.1 交互方式 (3)2.2 非交互方式 (3)三. TCL总体结构图 (4)四. 与其它语言的比较 (4)五. TCL语法 (5)5.1 t c l 命令结构. (5)5.2 TCL 的注释 (5)5.3 数据类型 (5)5.4 变量 (6)5.5 字符串的操作 (8)5.6 引用和置换 (10)5.7 流的控制 IF 和 SWITCH (12)5.8文件的输入输出和文件的信息 (14)5.9 过程 (16)六.工具箱 (17)6.1 构件的介绍 (17)6.2 创建构件 (18)6.3 构件的选项 (18)6.4 一个TCL./TK 构件的编程示例 (19)七. 小结 (20)Tcl / Tk 大全摘要: Tcl/Tk 是一种简明,高效,可移植性好的编程语言。

在信息产业领域具有广泛的应用。

本文描述了TCL/TK成长历史,特点,优势及应用范围,阐述了TCL/TK的总体结构图,比较了TCL/TK与当今流行的C++,Java 的性能比较,详细阐述了TCL/TK的语法,并介绍了TK的工具箱.一. Tcl / Tk简介1.1 背景Tcl/Tk 的发明人 John Ousterhout 教授在八十年代初,是伯克利大学的教授。

在其教学过程中,他发现在集成电路 CAD 设计中,很多时间是花在编程建立测试环境上。

并且,环境一旦发生了变化,就要重新修改代码以适应。

这种费力而又低效的方法,迫使Ousterhout 教授力图寻找一种新的编程语言,它即要有好的代码可重用性,又要简单易学,这样就促成了 Tcl (Tool Command Language) 语言的产生。

Tcl 最初的构想的是希望把编程按照基于组件的方法 (component approach),即与其为单个的应用程序编写成百上千行的程序代码,不如寻找一个种方法将程序分割成一个个小的, 具备一定“完整”功能的,可重复使用的组件。

Tcl编程教程(详细)

Tcl编程教程(详细)

Tcl编程初步编辑版本: 1.5日期:2004-3-2著者:陈涛上海贝尔阿尔卡特有限公司Tcl 编程初步总目录总目录................................................................................ . (I)例索引................................................................................ .. (IV)表索引................................................................................ .. (VI)图索引................................................................................ . (VII)第 1 章. TCL基本知识................................................................................ .. (1)1.1 什么是T CL................................................................................ (1)1.2 T CL自学工具................................................................................. (1)1.3 T CL软件包................................................................................. (2)1.4 T CL命令格式................................................................................. (2)1.5 T CL脚本文件和SOURCE 命令................................................................................. .. (3)1.6 可执行脚本文件(E XECUTABLEF ILE).............................................................................. . (3)1.7 获得帮助................................................................................. . (4)1.7.1 Windows系统................................................................................. . (4)1.7.2 Unix系统................................................................................. (4)第 2 章. 输出、赋值与替换................................................................................ (5)2.1 PUTS............................................................................... .. (5)2.2 SET & UNSET............................................................................... . (5)2.3 替换................................................................................. .. (6)2.3.1 $.................................................................................. .. (6)2.3.2 []................................................................................. .. (6)2.3.3 " " 和{}................................................................................. .. (6)2.3.4 \.................................................................................. .. (7)第 3 章. 数学表达式与EXPR命令................................................................................ .. (8)3.1 数学和逻辑运算符................................................................................. (8)3.2 数学函数................................................................................. . (8)3.3 数学运算举例................................................................................. . (9)3.4 INCR命令................................................................................. . (9)第 4 章. 字符串................................................................................ (10)4.1 基本命令集................................................................................. (10)4.2 APPEND命令................................................................................. .. (10)4.3 FORMAT命令................................................................................. .. (10)4.3.1 format命令说明................................................................................. (10)4.3.2 format举例................................................................................. .. (11)4.4 SCAN命令................................................................................. .. (12)4.5 BINARY命令................................................................................. (13)4.6 SUBST命令................................................................................. (14)4.7 STRING 命令................................................................................. (15)4.7.1 string 命令列表................................................................................. (15)4.7.2 字符串比较................................................................................. . (16)4.7.3 string match字符串匹配................................................................................. .. (16)4.7.4 字符串替换................................................................................. . (18)4.7.5 字符类别(class)测试................................................................................. . (18)4.7.6 字符串映射................................................................................. . (19)i Tcl 编程初步第 5 章. TCL列表操作................................................................................ (20)5.1 列表命令集................................................................................. (20)5.2 LIST命令................................................................................. . (20)5.3 CONCAT命令................................................................................. . (21)5.4 LAPPEND命令................................................................................. (21)5.5 LLENGTH 命令................................................................................. . (22)5.6 LINDEX命令................................................................................. . (22)5.7 LRANGE命令................................................................................. .. (22)5.8 LINSERT 和LREPLACE命令................................................................................. .. (22)5.9 LSEARCH命令................................................................................. . (23)5.10 LSORT命令................................................................................. .. (24)5.11 JOIN与SPLIT命令................................................................................. . (24)5.12 FOREACH控制结构................................................................................. . (27)第 6 章. 数组................................................................................ .. (28)6.1 数组的定义与格式................................................................................. . (28)6.2 数组变量................................................................................. . (29)6.3 多维数组................................................................................. . (29)6.4 数组操作命令................................................................................. .. (30)6.4.1 array get命令................................................................................. (30)6.4.2 array names命令................................................................................. . (30)6.4.3 遍历数组................................................................................. . (31)6.4.4 用数组定义结构................................................................................. .. (31)第7 章. 控制结构命令................................................................................ .. (32)7.1 IF/ELSE命令................................................................................. . (32)7.2 FOR命令................................................................................. . (33)7.3 WHILE命令................................................................................. .. (33)7.4 BREAK 与CONTINUE命令................................................................................. .. (34)7.5 SWITCH命令................................................................................. (34)7.6 CATCH 命令................................................................................. (35)7.7 ERROR命令................................................................................. . (36)7.8 RETURN 命令................................................................................. (37)7.9 EXIT命令................................................................................. . (37)第8 章. 过程与作用域................................................................................ .. (38)8.1 PROC—过程定义命令................................................................................. .. (38)8.2 作用域................................................................................. (40)8.2.1 过程的作用域................................................................................. (40)8.2.2 变量的作用域................................................................................. (40)8.3 UPVAR命令................................................................................. . (42)8.4 RENAME命令................................................................................. . (44)8.5 特殊变量................................................................................. . (45)8.5.1 命令行参数................................................................................. . (45)8.5.2 env--环境变量数组................................................................................. (45)8.6 EVAL命令................................................................................. (46)8.7 UPLEVEL命令................................................................................. (48)第9 章. 正则表达式(REGULAR EXPRESSIONS) (49)9.1 REGEXP命令................................................................................. .. (49)9.2 REGSUB命令................................................................................. (51)9.3 正则表达式的语法................................................................................. . (52)ii Tcl 编程初步9.3.1 分支(branch)和原子(atom)............................................................................. . (52)9.3.2 基本语法................................................................................. . (52)9.3.2.1 匹配字符.......................................................................................... .. (52)9.3.2.2 限定匹配.......................................................................................... .. (53)9.3.2.3 方括号表达式与字符集.......................................................................................... .. (53)9.3.2.4 匹配分支.......................................................................................... .. (54)9.3.2.5 量词(Qulifier)................................................................................ (54)9.3.2.6 子模式与匹配报告捕获.......................................................................................... .. (55)9.3.2.7 反斜杠引用.......................................................................................... . (56)9.3.2.8 匹配优先级.......................................................................................... . (56)9.3.3 高级正则表达式(AREs)........................................................................... .. (57)9.3.3.1 反斜杠换码(escape)序列.......................................................................................... (57)9.3.3.2 归整元素(collating element).................................................................................... .. (57)9.3.3.3 等价类(equivalence class)...................................................................................... (58)9.3.3.4 字符类(character class)...................................................................................... (58)9.3.3.5 非贪婪量词.......................................................................................... . (59)9.3.3.6 约束量词.......................................................................................... .. (59)9.3.3.7 回退引用.......................................................................................... .. (59)9.3.3.8 前瞻(lookahead)................................................................................. (60)9.3.3.9 换行符敏感的匹配.......................................................................................... . (60)9.3.3.10 嵌入式选项.......................................................................................... . (60)9.3.3.11 扩展语法.......................................................................................... (60)9.3.4 语法小结................................................................................. . (60)9.3.5 其它支持正则表达式的命令................................................................................. .. (60)第10 章. 名字空间................................................................................ (62)10.1 创建名字空间................................................................................. . (62)10.2 用::限定符来使用变量和过程................................................................................. . (62)10.3 名字空间的变量................................................................................. (63)10.4 过程的进口与出口................................................................................. (64)10.5 内省(INTROSPECTION)...................................................................... .. (65)10.6 名字空间命令集................................................................................. (65)第11 章. 跟踪与调试................................................................................ .. (67)11.1 CLOCK命令................................................................................. (67)11.1.1 clock clicks命令................................................................................. (67)11.1.2 clock seconds命令................................................................................. (67)11.1.3 clock format命令................................................................................. (68)11.1.4 clock scan命令................................................................................. . (70)11.2 INFO 命令................................................................................. . (71)11.2.1 info level.............................................................................. (72)11.2.2 info exists............................................................................. (72)11.3 TRACE命令................................................................................. . (73)11.3.1 trace variable........................................................................... (73)11.3.2 trace vdelete............................................................................ (75)11.3.3 trace vinfo.............................................................................. (75)第12 章. 脚本库与软件包................................................................................ . (76)12.1 声明和使用软件包................................................................................. (76)12.1.1 软件包定位................................................................................. . (76)12.1.2 声明软件包命令................................................................................. .. (76)12.1.3 加载软件包命令................................................................................. .. (76)12.1.4 自动加载与软件包索引................................................................................. (77)12.1.5 用链接库提供软件包................................................................................. . (79)iii Tcl 编程初步12.2 PACKAGE命令集................................................................................. . (80)12.3 小结................................................................................. .. (80)第13 章. 文件操作与程序调用................................................................................ (81)13.1 文件操作................................................................................. (81)13.1.1 文件I/O................................................................................ (81)13.1.2 文件系统信息命令................................................................................. .. (82)13.1.2.1 glob命令.......................................................................................... . (83)13.1.2.2 file命令集.......................................................................................... . (83)13.2 程序调用................................................................................. (85)13.2.1 用open命令打开一个进程管道 (85)13.2.2 用exec命令调用程序................................................................................. . (87)13.2.3 pid命令................................................................................. .. (88)第14 章. 套接字与事件驱动编程简介................................................................................ . (89)14.1 套接字编程................................................................................. .. (89)14.1.1 socket命令.................................................................................14.1.1.1 Client端socket命令.......................................................................................... .. (89)14.1.1.2 Server端socket命令选项.......................................................................................... (90)14.1.2 用fconfigure配置套接字................................................................................. . (90)14.1.3 C/S编程举例................................................................................. (90)14.2 事件驱动编程................................................................................. . (93)14.2.1 after命令................................................................................. .. (93)14.2.2 fileevent命令................................................................................. . (96)14.2.3 vwait命令................................................................................. . (96)14.2.4 fconfigure命令................................................................................. . (97)14.2.4.1 fconfigure语法.......................................................................................... .. (97)14.2.4.2 非阻塞I/O......................................................................................... .. (98)14.2.4.3 缓冲.......................................................................................... . (98)参考文献................................................................................ . (100)例索引例 1-1 输出一段字符串的例子.............................................................................例 1-2 source命令的简单例子............................................................................. (3)例 2-1 输出一个词的例子............................................................................. (5)例 2-2 参数定义、赋值与参数值引用............................................................................. (5)例 2-3 嵌套$用做替换操作............................................................................. (6)例 2-4 命令替换[]的例子............................................................................. (6)例 2-5 {}替换的例子............................................................................. (6)例 2-6 \的例子............................................................................. (7)例 2-7 不规范的续行............................................................................. (7)例 3-1 数学运算举例............................................................................. (9)例 4-1 append命令的简单例子............................................................................. (10)例 4-2 位置说明符的例子............................................................................. (11)例 4-3 format命令的简单例子............................................................................. (11)例 4-4 scan命令的简单例子............................................................................. (12)例 4-5 体验binary format 和binary scan的作用 (13)例 4-6 binary命令的简单应用.............................................................................例 4-7 subst命令的简单例子............................................................................. .. (14)例 4-8 string compare 和string equal进行字符串比较的例子 (16)iv Tcl 编程初步例 4-9字符串替换简单例子............................................................................. (18)例 5-1 使用list命令创建列表............................................................................. (20)例 5-2 concat命令的例子............................................................................. (21)例 5-3 lappend命令简单例子............................................................................. (21)例 5-4 llength命令的一个简单例子............................................................................. (22)例 5-5 lindex命令的一个简单例子............................................................................. (22)例 5-6linsert和lreplace命令的例子............................................................................. (22)例 5-7 lsearch命令的简单例子............................................................................. (23)例 5-8 lsearch与lreplace结合删除列表元素 (23)例 5-9 lsort命令简单的例子............................................................................. (24)例 5-10 split命令例子............................................................................. (24)例 5-11空元素与独立字符元素的split例子............................................................................. (24)例 5-12 用ldel删除指定元素............................................................................. (25)例 5-13 根据步长调整MAC地址值............................................................................. (25)例 5-14 foreach的简单例子:依次打印列表元素 (27)例 5-15具有多个值列表的foreach命令处理过程 (27)例 6-1 认识数组............................................................................. (28)例 6-2 混淆普通变量和数组时的错误例子............................................................................. (29)例 6-3 通过替换间接使用数组变量............................................................................. (29)例 6-4 数组和列表互换............................................................................. (30)例 6-5 array names的简单例子............................................................................. (31)例 6-6 遍历数组的一个方法举例............................................................................. (31)例 6-7 用数组来定义结构............................................................................. (31)例 7-1 if/else控制命令的简单例子............................................................................. (32)例 7-2 一个for循环............................................................................. (33)例 7-3 while循环的例子............................................................................. (34)例 7-4 switch 命令的简单例子............................................................................. (34)例 7-5 switch语句中不当注释引起的错误...............................................................................35例 7-6用catch捕获命令错误信息............................................................................. (35)例 7-7 error命令的例子............................................................................. (36)例 7-8用return命令从过程中返回............................................................................. (37)例 8-1 带有默认参数的过程定义............................................................................. (38)例 8-2 不定输入参数过程的例子............................................................................. (39)例 8-3参数名+参数值成对输入的过程定义............................................................................. (39)例 8-4 过程的定义............................................................................. (40)例 8-5 变量的作用域............................................................................. (40)例 8-6 全局变量与局部变量的关系............................................................................. (41)例 8-7 用”::”来声明全局变量............................................................................. (41)例 8-8 upvar命令的例子............................................................................. (42)例 8-9 通过upvar命令来传递数组............................................................................. (44)例 8-10 用rename命令来取消一个命令............................................................................. (44)例 8-11 打印命令行参数信息............................................................................. (45)例 8-12 用eval创建新命令的简单例子............................................................................. (46)例 8-13 动态定义过程............................................................................. (47)例 8-14 uplevel的简单例子............................................................................. (48)例 9-1 regexp的简单例子............................................................................. (50)例 9-2 用regsub进行字符串替换的简单例子 (5)1例 9-3 匹配挂靠的简单例子............................................................................. . (53)例 9-4 字符集匹配的例子............................................................................. .. (53)例 9-5 使用量词*和?不当引起的错误............................................................................. .. (55)v Tcl 编程初步例 9-6子模式捕获............................................................................. (55)例 9-7屏蔽子模式报告............................................................................. (55)例 9-8子模式综合运用的例子:搜索脚本文件中定义的过程 (55)例 9-9 归整元素匹配字符串............................................................................. (58)例 9-10字符类的简单例子............................................................................. (58)例 10-1定义名字空间Counter:....................................................................... (62)例 10-2 动态定义名字空间............................................................................. (62)例 10-3 限定名比较的简单例子............................................................................. (63)例 10-4 名字空间自动处理引用变量的归属............................................................................. (64)例 10-5 过程的进口与出口的简单例子............................................................................. (64)例 10-6 namespace origin命令例子............................................................................. (65)例 11-1计算系统时钟滴答数............................................................................. (67)例 11-2clock format在windows上的简单例子 (69)例 11-3 Tcl识别的系统编码方式............................................................................. (69)例 11-4 消除clock format输出中的乱码............................................................................. (70)例 11-5 用info测试变量是否存在............................................................................. (71)例 11-6 用info level命令控制过程的循环嵌套 (72)例 11-7 用trace variable跟踪变量的简单例子 (73)例 11-8 trace vinfo 的例子............................................................................. . (75)例 12-1 auto_path的内容与操作............................................................................. (76)例 12-2 pkg_mkIndex命令............................................................................. . (77)例 12-3 简单的软件包加载的例子............................................................................. . (78)例 13-1用open命令打开文件,并输入数据.............................................................................82例 13-2 lstat和 stat命令举例............................................................................. . (84)例 13-3 用open命令打开只读进程管道............................................................................. (86)例 13-4 用open命令打开进程管道又一例............................................................................. . (86)例 13-5 用exec处理管道与I/O重定向............................................................................. .. (87)例 13-6 用pid命令检查进程ID............................................................................. . (88)例 14-1基于socket实现的C/S(Client/Server)简单模型 (90)例 14-2 after 命令的简单应用............................................................................. (94)例 14-3vwait命令的简单例子............................................................................. (97)。

TCL培训教程2024

TCL培训教程2024

引言:TCL培训教程(二)作为继TCL培训教程(一)之后的延续,旨在进一步深入介绍TCL脚本语言的各个方面。

本文将通过引言概述、正文内容和总结来详细探讨TCL的高级特性与应用,并提供详细的示例和实践指导。

概述:在本文中,我们将重点介绍TCL中的5个大点,包括TCL脚本的文件操作、正则表达式的使用、错误处理和异常处理、TCL的面向对象编程以及和其他编程语言的互操作性。

每个大点将包含5-9个小点,以便更全面地探讨TCL的各个方面。

正文内容:一、TCL脚本的文件操作:1. 文件读取和写入操作:介绍如何使用TCL脚本读取和写入文件,并讨论文件的打开和关闭操作。

2. 文件操作函数:详细介绍TCL中用于文件操作的常用函数和命令,如文件重命名、文件删除等。

3. 文件路径处理:讨论如何处理文件路径,包括相对路径和绝对路径的转换。

4. 文件权限和属性:介绍如何获取和修改文件的权限和属性信息,以及相关的TCL命令。

5. 文件夹操作:介绍如何操作文件夹,包括创建文件夹、删除文件夹以及遍历文件夹内的文件。

二、正则表达式的使用:1. 正则表达式的基本语法:介绍正则表达式的基本语法和元字符的使用方法。

2. 正则表达式的匹配与替换:详细探讨如何使用TCL的正则表达式进行字符串的匹配和替换。

3. 正则表达式的捕获组:介绍如何使用捕获组来提取正则表达式匹配的子串。

4. 正则表达式的高级应用:探讨正则表达式在TCL中的高级应用,如贪婪匹配、非贪婪匹配等。

5. 正则表达式的性能优化:讨论如何优化正则表达式的性能,避免正则表达式的过度复杂。

三、错误处理和异常处理:1. 错误处理的基本概念:介绍错误处理的基本概念和原则,以及TCL内置的错误处理机制。

2. 错误处理命令:详细介绍TCL中的错误处理命令,如catch、error、return等。

3. 异常处理的基本原则:讨论异常处理的基本原则和最佳实践。

4. 异常处理命令:介绍TCL中的异常处理命令,如try、throw等。

tcl中while语句

tcl中while语句

tcl中while语句TCL是一种脚本语言,很多时候我们需要使用一些循环语句来完成特定的任务。

其中while循环是TCL语言中最常用的循环语句之一。

本文将围绕“TCL中while语句”展开阐述,分步骤来介绍如何在TCL中使用while循环。

第一步:while循环的基本语法while循环的基本语法如下所示:while 条件语句 {循环体}其中,条件语句可以是任何TCL合法的表达式,循环体是需要重复执行的一段代码块。

while循环的执行顺序为:首先判断条件语句是否为真,如果为真则执行循环体,然后再次判断条件语句是否为真。

如果条件语句一直为真,则会一直执行循环体。

当条件语句为假时,while循环结束。

第二步:while循环的使用案例下面举一个while循环的实例来说明如何在TCL中使用while循环。

我们要求计算从1到10的和,具体代码如下所示:set i 1set sum 0while {$i <= 10} {set sum [expr {$sum + $i}]set i [expr {$i + 1}]}puts "1到10的和为:$sum"在上面的代码中,我们首先使用set命令定义了变量i和sum的初始值分别为1和0,然后使用while循环来计算1到10的和。

在循环体中,我们使用了set命令对sum变量的值进行累加,并使用set命令对i变量的值加1。

当i的值达到10时,条件语句$i <= 10$不再为真,while循环终止,输出计算结果。

第三步:while循环的注意事项在使用while循环时,需要注意以下几点:1. 一定要设置好循环的结束条件,否则循环会变成无限循环。

2. 循环不要嵌套过多,否则代码可读性和易维护性会降低。

3. 尽量避免使用while循环来处理大量数据,因为while循环会不断判断条件语句,会导致性能下降。

总结本文围绕“TCL中while语句”展开阐述,分步骤来介绍了如何在TCL中使用while循环。

tcl语言中switch语句的用法及规则

tcl语言中switch语句的用法及规则

tcl语言中switch语句的用法及规则
在TCL(Tool Command Language)中,switch语句用于基于不同的条件执行不同的代码块。

它的用法和规则如下:
语法:
tcl复制代码
switch expression {
pattern1 {
# 代码块1
}
pattern2 {
# 代码块2
}
...
default {
# 默认代码块
}
}
规则:
1.expression:要评估的表达式或变量。

2.pattern:与expression进行匹配的模式。

可以使用简单的字符串模式或正则表达式
模式。

3.default:可选的默认代码块,当没有任何模式与expression匹配时执行。

4.每个模式后面可以跟随一个代码块,当模式匹配成功时执行该代码块。

5.如果多个模式与expression匹配,TCL 将只执行第一个匹配的模式。

6.如果省略default代码块,并且没有任何模式与expression匹配,则不会执行任何
代码块。

注意事项:
•在switch语句中,可以使用正则表达式模式进行匹配,但需要注意的是,TCL 的正则表达式语法与常见的正则表达式语法略有不同。

•在使用switch语句时,要确保每个模式都是唯一的,以避免意外的行为。

•如果要使用多个模式匹配相同的代码块,可以使用break命令来跳出switch语句的执行。

•switch语句在某些情况下可能不是最佳选择,特别是当有大量模式需要匹配时。

在这种情况下,使用if-elseif-else结构可能更为清晰和易于维护。

tcl foreach用法

tcl foreach用法

tcl foreach用法tcl中有很多用于循环的命令,其中一个常用的是foreach命令。

foreach命令用于在一个列表中循环,并对每个元素执行一些操作。

以下是foreach命令的基本语法:foreach 变量名列表 {#执行的语句}其中,变量名是循环过程中每个元素的名称,列表是要循环的元素列表,可以是一个列表变量,也可以是一个由空格分隔的元素列表。

以下是一个foreach循环的示例:set fruits {apple banana orange}foreach fruit $fruits {puts 'I like $fruit'}在上面的示例中,foreach循环遍历了fruits列表中的每个元素,并将它们赋值给变量fruit。

然后,在每次迭代中,循环体中的代码将该变量插入到字符串中,并输出到屏幕上。

除了基本语法,foreach命令还支持一些高级用法,如使用多个变量、使用范围和步长等。

以下是一些示例:1. 使用多个变量:set numbers {1 2 3}set letters {a b c}foreach num $numbers let $letters {puts '$num is $let'}在上面的示例中,foreach循环遍历了两个列表,将每个列表中的元素赋值给相应的变量。

然后,在每次迭代中,循环体中的代码将这些变量插入到字符串中,并输出到屏幕上。

2. 使用范围和步长:foreach i {0 2 4 6 8} {puts $i}在上面的示例中,foreach循环使用了范围和步长,从0开始,步长为2,直到达到8。

总之,foreach命令是一个强大的循环工具,可以帮助我们在tcl 脚本中高效地处理各种列表和数组。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C H A P T E R21 Multi-Threaded Tcl ScriptsThis chapter describes the Thread extension for creating multi-threaded Tcl scripts.This Chapter is from Practical Programming in Tcl and Tk, 4th Ed.Copyright 2003 © Brent Welch, Ken Jones/book/T hread support, a key feature of manylanguages, is a recent addition to Tcl. That’s because the Tcl event loop supports features implemented by threads in most other languages, such as graphical user interface management, multi-client servers, asynchronous communication, and scheduling and timing operations. However, although Tcl’s event loop can replace the need for threads in many circumstances, there are still some instances where threads can be a better solution:•Long-running calculations or other processing, which can “starve” the event loop•Interaction with external libraries or processes that don’t support asynchro-nous communication•Parallel processing that doesn’t adapt well to an event-driven model •Embedding Tcl into an existing multi-threaded applicationWhat are Threads?Traditionally, processes have been limited in that they can do only one thing at a time. If your application needed to perform multiple tasks in parallel, you designed the application to create multiple processes. However, this approach has its drawbacks. One is that processes are relatively “heavy” in terms of the resources they consume and the time it takes to create them. For applications that frequently create new processes — for example, servers that create a new321322 Multi-Threaded Tcl Scripts Chap. 21 process to handle each client connection — this can lead to decreased response time. And widely parallel applications that create many processes can consume so many system resources as to slow down the entire system. Another drawback is that passing information between processes can be slow because most inter-process communication mechanisms — such as files, pipes, and sockets —involve intermediaries such as the file system or operating system, as well as requiring a context switch from one running process to another.Threads were designed as a light-weight alternative. Threads are multiple flows of execution within the same process. All threads within a process share the same memory and other resources. As a result, creating a thread requires far fewer resources than creating a separate process. Furthermore, sharing informa-tion between threads is much faster and easier than sharing information between processes.The operating system handles the details of thread creation and coordina-tion. On a single-processor system, the operating system allocates processor time to each of an application’s threads, so a single thread doesn’t block the rest of the application. On multi-processor systems, the operating system can even run threads on separate processors, so that threads truly can run simultaneously.The drawback to traditional multi-threaded programming is that it can be difficult to design a thread-safe application — that is, an application in which one thread doesn’t corrupt the resources being used by another thread. Because all resources are shared in a multi-threaded application, you need to use various locking and scheduling mechanisms to guard against multiple threads modifying resources concurrently.Thread Support in TclTcl added support for multi-threaded programming in version 8.1. The Tcl core was made thread-safe. Furthermore, new C functions exposed “platform-neutral”thread functionality. However, no official support was provided for multi-threaded scripting. Since then, the Thread extension — originally written by Brent Welch and currently maintained by Zoran Vasiljevic — has become the accepted mechanism for creating multi-threaded Tcl scripts. The most recent version of the Thread extension as this was being written was 2.5. In general, this version requires Tcl 8.3 or later, and several of the commands provided require Tcl 8.4 or later.At the C programming level, Tcl’s threading model requires that a Tcl interpreter be managed by only one thread. However, each thread can create as many Tcl interpreters as needed running under its control. As is the case in even a single-threaded application, each Tcl interpreter has its own set of variables and procedures. A thread can execute commands in another thread’s Tcl inter-preter only by sending special messages to that interpreter’s event queue. Those messages are handled in the order received along with all other types of events.Thread Support in Tcl323 Obtaining a Thread-Enabled Tcl InterpreterMost binary distributions of Tcl are not thread-enabled, because the defaultoptions for building the Tcl interpreters and libraries do not enable thread sup-port. Thread safety adds overhead, slowing down single-threaded Tcl applica-tions, which constitute the vast majority of Tcl applications. Also, many Tclextensions aren’t thread safe, and naively trying to use them in a multi-threadedapplication can cause errors or crashes.Unless you can obtain a thread-enabled binary distribution of Tcl, you mustcompile your own from the Tcl source distribution. This requires running the configure command with the --enable-threads option during the build pro-cess. (See Chapter 48, “Compiling Tcl and Extensions” for more information.)You can test whether a particular Tcl interpreter is thread-enabled bychecking for the existence of the tcl_platform(threaded) element. This ele-ment exists and contains a Boolean true value in thread-enabled interpreters,whereas it doesn't exist in interpreters without thread support.Using Extensions in Multi-Threaded ScriptsBecause each interpreter has its own set of variables and procedures, youmust explicitly load an extension into each thread that wants to use it. Only the Thread extension itself is automatically loaded into each interpreter.You must be careful when using extensions in multi-threaded scripts. ManyTcl extensions aren’t thread-safe. Attempting to use them in multi-threadedscripts often results in crashes or corrupted data.Tcl-only extensions are generally thread-safe. Of course, they must makeno use of other commands or extensions that aren’t thread-safe. But otherwise,multi-threaded operation doesn’t add any new issues that don't already affectsingle-threaded scripts.You should always assume that a binary extension is not thread-safe unlessits documentation explicitly says that it is. And even thread-safe binary exten-sions must be compiled with thread support enabled for you to use them inmulti-threaded applications. (The default compilation options for most binaryextensions don’t include thread support.)Tk isn’t truly thread-safe.Most underlying display libraries (such as X Windows) aren’t thread safe —or at least aren’t typically compiled with thread-safety enabled. However, signif-icant work has gone into making the Tk core thread-safe. The result is that youcan safely use Tk in a multi-threaded Tcl application as long as only one threaduses Tk commands to manage the interface. Any other thread that needs toupdate the interface should send messages to the thread controlling the inter-face.324 Multi-Threaded Tcl Scripts Chap. 21 Getting Started with the Thread ExtensionYou start a thread-enabled tclsh or wish the same as you would a non-threaded tclsh or wish. When started, there is only one thread executing, often referred to as the main thread, which contains a single Tcl interpreter. If you don’t create any more threads, your application runs like any other single-threaded applica-tion.Make sure that the main thread is the last one to terminate.The main thread has a unique position in a multi-threaded Tcl script. If it exits, then the entire application terminates. Also, if the main thread terminates while other threads still exist, Tcl can sometimes crash rather than exiting cleanly. Therefore, you should always design your multi-threaded applications so that your main thread waits for all other threads to terminate before it exits.Before accessing any threading features from your application, you must load the Thread extension:package require ThreadThe Thread extension automatically loads itself into any new threads your application creates with thread::create. All other extensions must be loaded explicitly into each thread that needs to use them. The Thread extension creates commands in three separate namespaces:•The thread namespace contains all of the commands for creating and man-aging threads, including inter-thread messaging, mutexes, and condition variables.•The tsv namespace contains all of the commands for creating and managing thread shared variables.•The tpool namespace contains all of the commands for creating and manag-ing thread pools.Creating ThreadsThe thread::create command creates a new thread containing a new Tcl interpreter. Any thread can create another thread at will; you aren’t limited to starting threads from only the main thread. The thread::create command returns immediately, and its return value is the ID of the thread created. The ID is a unique token that you use to interact with and manipulate the thread, in much the same way as you use a channel identifier returned by open to interact with and manipulate that channel. There are several commands available for introspection on thread IDs: thread::id returns the ID of the current thread; thread::names returns a list of threads currently in existence; and thread::exists tests for the existence of a given thread.The thread::create command accepts a Tcl script as an argument. If you provide a script, the interpreter in the newly created thread executes it and then terminates the thread. Example 21–1 demonstrates this by creating a thread to perform a recursive search for files in a directory. For a large directory structure,Getting Started with the Thread Extension325 this could take considerable time. By performing the search in a separate thread, the main thread is free to perform other operations in parallel. Also note how the “worker” thread loads an extension and opens a file, completely independent of any extensions loaded or files opened in other threads.Example 21–1Creating a separate thread to perform a lengthy operation.package require Thread# Create a separate thread to search the current directory# and all its subdirectories, recursively, for all files# ending in the extension ".tcl". Store the results in the# file "files.txt".thread::create {# Load the Tcllib fileutil package to use its# findByPattern procedure.package require fileutilset files [fileutil::findByPattern [pwd] *.tcl]set fid [open files.txt w]puts $fid [join $files \n]close $fid}# The main thread can perform other tasks in parallel...If you don’t provide a script argument to thread::create, the thread’s interpreter enters its event loop. You then can use the thread::send command, described on page 328, to send it scripts to evaluate. Often though, you’d like to perform some initialization of the thread before having it enter its event loop. To do so, use the thread::wait command to explicitly enter the event loop after per-forming any desired initialization, as shown in Example 21–2. You should always use thread::wait to cause a thread to enter its event loop, rather than vwait or tkwait, for reasons discussed in “Preserving and Releasing Threads” on page 330.Example 21–2Initializing a thread before entering its event loop.set httpThread [thread::create {package require httpthread::wait}]After creating a thread, never assume that it has started executing.There is a distinction between creating a thread and starting execution of a thread. When you create a thread, the operating system allocates resources for326 Multi-Threaded Tcl Scripts Chap. 21 the thread and prepares it to run. But after creation, the thread might not start execution immediately. It all depends on when the operating system allocates execution time to the thread. Be aware that the thread::create command returns when the thread is created, not necessarily when it has started. If your application has any inter-thread timing dependencies, always use one of the thread synchronization techniques discussed in this chapter.Creating Joinable ThreadsRemember that the main thread must be the last to terminate. Therefore you often need some mechanism for determining when it’s safe for the main thread to exit. Example 21–3 shows one possible approach: periodically checking thread::names to see if the main thread is the only remaining thread.Example 21–3Creating several threads in an application.package require Threadputs "*** I'm thread [thread::id]"# Create 3 threadsfor {set thread 1} {$thread <= 3} {incr thread} {set id [thread::create {# Print a hello message 3 times, waiting# a random amount of time between messagesfor {set i 1} {$i <= 3} {incr i} {after [expr { int(500*rand()) }]puts "Thread [thread::id] says hello"}}] ;# thread::createputs "*** Started thread $id"} ;# forputs "*** Existing threads: [thread::names]"# Wait until all other threads are finishedwhile {[llength [thread::names]] > 1} {after 500}puts "*** That's all, folks!"A better approach in this situation is to use joinable threads, which are supported in Tcl 8.4 or later. A joinable thread allows another thread to wait upon its termination with the thread::join command. You can useGetting Started with the Thread Extension327 thread::join only with joinable threads, which are created by including the thread::create-joinable option. Attempting to join a thread not created with -joinable results in an error. Failing to join a joinable thread causes memoryand other resource leaks in your application. Example 21–4 revises the program from Example 21–3 to use joinable threads.Example 21–4Using joinable threads to detect thread termination.package require Threadputs "*** I'm thread [thread::id]"# Create 3 threadsfor {set thread 1} {$thread <= 3} {incr thread} {set id [thread::create -joinable {# Print a hello message 3 times, waiting# a random amount of time between messagesfor {set i 1} {$i <= 3} {incr i} {after [expr { int(500*rand()) }]puts "Thread [thread::id] says hello"}}] ;# thread::createputs "*** Started thread $id"lappend threadIds $id} ;# forputs "*** Existing threads: [thread::names]"# Wait until all other threads are finishedforeach id $threadIds {thread::join $id}puts "*** That's all, folks!"The thread::join command blocks.Be aware that thread::join blocks. While the thread is waiting for thread::join to return, it can’t perform any other operations, including servic-ing its event loop. Therefore, make sure that you don’t use thread::join in situ-ations where a thread must be responsive to incoming events.328 Multi-Threaded Tcl Scripts Chap. 21 Sending Messages to ThreadsThe thread::send command sends a script to another thread to execute. The target thread’s main interpreter receives the script as a special type of event added to the end of its event queue. A thread evaluates its messages in the order received along with all other types of events. Obviously, a thread must be in its event loop for it to detect and respond to messages. As discussed on page 324, a thread enters its event loop if you don’t provide a script argument to thread::create, or if you include the thread::wait command in the thread’s initialization script.Synchronous Message SendingBy default, thread::send blocks until the target thread finishes executing the script. The return value of thread::send is the return value of the last com-mand executed in the script. If an error occurs while evaluating the script, the error condition is “reflected” into the sending thread; thread::send generates the same error code, and the target thread’s stack trace is included in the value of the errorInfo variable of the sending thread:Example 21–5Examples of synchronous message sending.set t [thread::create];# Create a thread=> 1572set myX 42;# Create a variable in the main thread=> 42# Copy the value to a variable in the worker threadthread::send $t [list set yourX $myX]=> 42# Perform a calculation in the worker threadthread::send $t {expr { $yourX / 2 } }=> 21thread::send $t {expr { $yourX / 0 } }=> divide by zerocatch {thread::send $t {expr { $yourX / 0 } } } ret=> 1puts $ret=> divide by zeroputs $errorInfo=> divide by zerowhile executing"expr { $yourX / 0 } "invoked from within"thread::send $t {expr { $yourX / 0 } } "If you also provide the name of a variable to a synchronous thread::send, then it behaves analogously to a catch command; thread::send returns the return code of the script, and the return value of the last command executed inSending Messages to Threads329 the script — or the error message — is stored in the variable. Tcl stores the tar-get thread’s stack trace in the sending thread’s errorInfo variable.Example 21–6Using a return variable with synchronous message sending.thread::send $t {incr yourX 2} myY=> 0puts $myY=> 44thread::send $t {expr { acos($yourX) } } ret=> 1puts $ret=> domain error: argument not in valid rangeputs $errorInfo=> domain error: argument not in valid rangewhile executing"expr { acos($yourX) } "While the sending thread is waiting for a synchronous thread::send to return, it can’t perform any other operations, including servicing its event loop. Therefore, synchronous sending is appropriate only in cases where:•you want a simple way of getting a value back from another thread;•you don’t mind blocking your thread if the other thread takes a while to respond; or•you need a response from the other thread before proceeding.Watch out for deadlock conditions with synchronous message sending.If Thread A performs a synchronous thread::send to Thread B, and while evaluating the script Thread B performs a synchronous thread::send to Thread A, then your application is deadlocked. Because Thread A is blocked in its thread::send, it is not servicing its event loop, and so can’t detect Thread B’s message.This situation arises most often when the script you send calls procedures in the target thread, and those procedures contain thread::send commands. Under these circumstances, it might not be obvious that the script sent will trig-ger a deadlock condition. For this reason, you should be cautious about using synchronous thread::send commands for complex actions. Sending in asynchro-nous mode, described in the next section, avoids potential deadlock situations like this.Asynchronous Message SendingWith the -async option, thread::send sends the script to the target thread in asynchronous mode. In this case, thread::send returns immediately.By default, an asynchronous thread::send discards any return value of the script. However, if you provide the name of a variable as an additional argument to thread::send, the return value of the last command executed in the script is330 Multi-Threaded Tcl Scripts Chap. 21 stored as the value of the variable. You can then either vwait on the variable or create a write trace on the variable to detect when the target thread responds. For example:thread::send -async $t [list ProcessValues $vals] resultvwait resultIn this example, the thread::send command returns immediately; the sending thread could then continue with any other operations it needed to per-form. In this case, it executes a vwait on the return variable to wait until the tar-get thread finishes executing the script. However, while waiting for the response, it can detect and process incoming events. In contrast, the following synchronous thread::send blocks, preventing the sending thread from processing events until it receives a response from the target thread:thread::send $t [list ProcessValues $vals] result Preserving and Releasing ThreadsA thread created with a script not containing a thread::wait command termi-nates as soon as the script finishes executing. But if a thread enters its event loop, it continues to run until its event loop terminates. So how do you terminate a thread’s event loop?Each thread maintains an internal reference count. The reference count is set initially to 0, or to 1 if you create the thread with the thread::create -pre-served option. Any thread can increment the reference count afterwards by exe-cuting thread::preserve, and decrement the reference count by executing thread::release. These commands affect the reference count of the current thread unless you specify the ID of another thread. If a call to thread::release results in a reference count of 0 or less, the thread is marked for termination.The use of thread reference counts allows multiple threads to preserve the existence of a worker thread until all of the threads release the worker thread. But the majority of multi-threaded Tcl applications don’t require that degree of thread management. In most cases, you can simply create a thread and then later use thread::release to terminate it:set worker [thread::create]thread::send -async $worker $script# Later in the program, terminate the worker threadthread::release $workerA thread marked for termination accepts no further messages and discards any pending events. It finishes processing any message it might be executing currently, then exits its event loop. If the thread entered its event loop through a call to thread::wait, any other commands following thread::wait are executed before thread termination, as shown in Example 21–7. This can be useful for per-forming “clean up” tasks before terminating a thread.Error Handling331 Example 21–7Executing commands after thread::wait returns.set t [thread::create {puts "Starting worker thread"thread::wait# This is executed after the thread is releasedputs "Exiting worker thread"}]Note that if a thread is executing a message script when thread::release is called (either by itself or another thread), the thread finishes executing its message script before terminating. So, if a thread is stuck in an endless loop, calling thread::release has no effect on the thread. In fact, there is no way to kill such a “runaway thread.”Always use thread::wait to enter a thread’s event loop.This system for preserving and releasing threads works only if you use the thread::wait command to enter the thread’s event loop (or if you did not provide a creation script when creating the thread). If you use vwait or tkwait to enter the event loop, thread::release cannot terminate the thread.Error HandlingIf an error occurs while a thread is executing its creation script (provided by thread::create), the thread dies. In contrast, if an error occurs while processing a message script (provided by thread::send), the default behavior is for the thread to stop execution of the message script, but to return to its event loop and continue running. To cause a thread to die when it encounters an uncaught error, use the thread::configure command to set the thread’s -unwindonerror option to true:thread::configure $t -unwindonerror 1Error handling is determined by the thread creating the thread or sending the message. If an error occurs in a script sent by a synchronous thread::send, then the error condition is “reflected” to the sending thread, as described in “Syn-chronous Message Sending” on page 328. If an error occurs during thread cre-ation or an asynchronous thread::send, the default behavior is for Tcl to send a stack trace to the standard error channel. Alternatively, you can specify the name of your own custom error handling procedure with thread::errorproc. Tcl automatically calls your procedure whenever an “asynchronous” error occurs, passing it two arguments: the ID of the thread generating the error, and the stack trace. (This is similar to defining your own bgerror procedure, as described in “The bgerror Command” on page 202.) For example, the following code logs all uncaught errors to the file errors.txt:332 Multi-Threaded Tcl Scripts Chap. 21 Example 21–8Creating a custom thread error handler.set errorFile [open errors.txt a]proc logError {id error} {global errorFileputs $errorFile "Error in thread $id"puts $errorFile $errorputs $errorFile ""}thread::errorproc logErrorShared ResourcesThe present working directory is a resource shared by all interpreters in all threads. If one thread changes the present working directory, then that change affects all interpreters and all threads. This can pose a significant problem, as some library routines temporarily change the present working directory during execution, and then restore it before returning. But in a multi-threaded applica-tion, another thread could attempt to access the present working directory dur-ing this period and get incorrect results. Therefore, the safest approach if your application needs to access the present working directory is to store this value in a global or thread-shared variable before creating any other threads. The follow-ing example uses tsv::set to store the current directory in the pwd element of the application shared variable:package require Thread# Save the pwd in a thread-shared variabletsv::set application pwd [pwd]set t [thread::create {#...}]Environment variables are another shared resource. If one thread makes a change to an environment variable, then that change affects all threads in your application. This might make it tempting to use the global env array as a method for sharing information between threads. However, you should not do so, because it is far less efficient than thread-shared variables, and there are subtle differ-ences in the way environment variables are handled on different platforms. If you need to share information between threads, you should instead use thread-shared variables, as discussed in “Shared Variables” on page 337.The exit command kills the entire application.Although technically not a shared resource, it’s important to recognize that the exit command kills the entire application, no matter which thread executes it. Therefore, you should never call exit from a thread when your intention is to terminate only that thread.Managing I/O Channels333 Managing I/O ChannelsChannels are shared resources in most programming languages. But in Tcl, channels are implemented as a per-interpreter resource. Only the standard I/O channels (stdin, stdout, and stderr) are shared.Be careful with standard I/O channel on Windows and Macintosh.When running wish on Windows and Macintosh prior to OS X, you don’t have real standard I/O channels, but simulated stdout and stderr channels direct output to the special console window. As of Thread 2.5, these simulated channels appear in the main thread’s channel list, but not in any other thread’s channel list. Therefore, you’ll cause an error if you attempt to access these chan-nels from any thread other than the main thread.Accessing Files from Multiple ThreadsIn a multi-threaded application, avoid having the same file open in multiple threads. Having the same file open for read access in multiple threads is safe, but it is more efficient to have only one thread read the file and then share the information with other threads as needed. Opening the same file in multiple threads for write or append access is likely to fail. Operating systems typically buffer information written to a disk on a per-channel basis. With multiple chan-nels open to the same file, it’s likely that one thread will end up overwriting data written by another thread. If you need multiple threads to have write access to a single file, it’s far safer to have one thread responsible for all file access, and let other threads send messages to the thread to write the data. Example 21–9 shows the skeleton implementation of a logging thread. Once the log file is open, other threads can call the logger’s AddLog procedure to write to the log file.Example 21–9A basic implementation of a logging thread.set logger [thread::create {proc OpenLog {file} {global fidset fid [open $file a]}proc CloseLog {} {global fidclose $fid}proc AddLog {msg} {global fidputs $fid $msg}thread::wait}]。

相关文档
最新文档