为啥在多模块调试的情况下$monitor需要配合$monitoron和$monitoroff来工作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为啥在多模块调试的情况下$monitor需要配合$monitoron和$monitoroff来工作相关的知识,希望对你有一定的参考价值。

参考技术A 1.系统任务 $monitor格式:$monitor(p1,p2,….pn);$monit0r;$monitoron;$monitoroff;任务$monitor提供了监视和输出参数列表中的表达式或变量的功能。其参数列表中输出控制格式字符串和输出列表的规则和$display中一样。当启动一个带有一个或多个参数的$monitor任务时,仿真器则建立一个处理机制,使得每当参数列表中变量或表达式的值发生变化时,整个参数列表中的变量或表达式的值都输出显示。如果同一时刻,两个或多个参数的值发生变化则在该时刻只输出一次。但在$monitor中,参数可以是$time系统函数。$monitoron和$monitoroff任务的作用是通过打开和关闭监控标志来控制监控任务$monitor的启动和停止,这样就可以控制$monitor的发生。其中$monitoroff任务用于关闭监控标志,停止监控任务$monitor,$monitoron则用来打开监控标志,启动监控任务$monitor。通常在通过调用$monitoron来启动$monitor时,不管$monitor参数列表中的值是否发生变化,总是立刻输出显示当前的时刻参数列表中的值,这用于在监视的初始时刻设定初始比较值。在默认情况下,控制标志在仿真的起始刻就已经打开了。在多模块调试的情况下,许多模块中都调用了$monitor,因为任何时刻只能有宇哥$monitor起作用,因此需配合$monitoron与$monitoroff使用,把需要监视的模块用$monitoron打开,在监视完毕后及时用$monitoroff关闭,以便把$monitor让给其他模块使用。$monitor与$display的不同处还在于$monitor往往在initial块中调用,只要不调用$monitoroff,$monitoron便不间断地对所设定的信号进行监视。2.时间度量系统函数$time(1)系统函数$time$time可以返回一个64位的整数来表示的当前仿真时刻值。该时刻是以模块的仿真时间尺度为基准的。(2)$realtime

系统函数$realtime和$time的作用是一样的,只是$realtime返回的时间数字是一个实型数,该数字也是以时间尺度为基准的。3.系统任务$finish格式:$finish;$finish(n);系统任务$finish的作用是退出仿真器。也可以带参数,根据参数的值输出不同的特征信息。如果不带参数,默认$finish的参数树枝为1.0
不输出任何信息;1 输出当前仿真时刻和位置;2
输出当前仿真时刻,位置和在仿真过程中所用memory及CPU的时间统计。4.系统任务$stop格式:$stop;$stop(n);$stop任务的作用是把EDA工具置成暂停模式,在仿真环境下给出一个交互式的命令提示符,将控制权交给用户。这个任务可以带有参数表达式。5.系统任务$readmemb和$readmemh用来从文件中读取数据到存储器中。这两个系统任务可以在仿真的任意时刻被执行,格式:(1)$readmemb("<数据文件名>",<存储器名>);(2)$readmemb("<数据文件名>",<存储器名>,<起始地址>);(3)$readmemb("<数据文件名>",<存储器名>,<起始地址>,<结束地址>);(4)$readmemh("<数据文件名>",<存储器名>);(5)$readmemh("<数据文件名>",<存储器名>,<起始地址>);(6)$readmemh("<数据文件名>",<存储器名>,<起始地址>,<结束地址>);在这两个系统任务中,被读取的数据文件的内容只能包含:空白位置(空格、换行、制表符(tab)和form-feeds),注释行(//形式的和形式的都允许)、二进制或十六进制的数字。数字中不能包含位宽的说明和格式说明,对与$readmemb系统任务,每个数字必须是二进制数,对于$readmemh系统任务,每个数字必须是十六进制。数字中不定值x或X,高阻值z或Z和下划线的使用方法及代表的意义与一般VERILOG

HDL程序的语法和用意一样6.系统任务$random这个系统函数提供了一个产生随机数的手段。当函数被调用时返回一个32位的随机数。他是一个带符号的整数。$random一般用法是:$random%b,其中b>0。他给出一个范围在(-b+1):(b-1)中的随机数。7.编译预处理(1)宏定义`define用一个指定的标识符来代表一个字符串,他的一般形式为:`define标识符(宏名)字符串(宏内容)这种方法可以以一个简单的的名字代替一个长的字符串,也可以用一个有含义的名字来代替没有含义的数字和符号。说明:1)宏名可以用大些字母也可以用小写字母。建议用大些!2)`define命令可以出现在模块定义里面,也可以出现在模块定义外面。红名的有效范围为定义命令之后到原文结束,通常定义在模块外面,作为程序的一部分,在此程序有效。3)在引用一定义的宏名时,必须在宏名的前面加上符号“`”,表示该名字是个经过宏定义的名字。4)使用宏定义可以提高程序的可移植性和可读性。5)宏定义是用宏名代替一个字符串,也就是做简单的置换,不做语法检查。预处理时照样带如,不管是否正确。只有在编译已被宏展开的源程序才报错。6)宏定义不是Verilog语句,不必在行末加分号。如果加了分号会连分号一起进行置换。7)在进行宏定义时,可以引用已定义的宏名,可以层层置换。8)宏名和宏内容必须在同一行中进行声明。如果在宏内容中包含有注释行,注释行不会作为被置换的内容。(2)“文件包含”处理`include所谓“文件包含”处理是一个源文件可以将另外的源文件的全部内容包含进来,即另外的文件包含到本文件之中。可以节省设计时间;可以将一些常用的的宏定义或任务组成一个文件夹,然后将这些宏定义包含到自己所写的源程序中。说明:1)一个`include命令只能指定一个被包含的文件,如果包含n个文件要用n个`include命令。2)`include命令可以出现在Verilog源程序的任何地方,被包含的文件名可以是相对路径也可以是绝对路径。3)可以将多个`include命令写在一行,在`include命令行,可以出现空格和注释行。4)如果文件1包含文件2,文件2要用到文件3的内容,则在文件1用两个`include分别包含文件2和文件3,而且文件3应出现在文件2之前。这样,文件1和文件2都可以用到文件3中的内容。在文件2中不必在用`include了。5)在一个被包含文件中又可以包含另一个被包含的文件,即文件包含可以是嵌套的。(3)时间尺度`timescale`timescale命令用来说明跟在该命令后的模块的时间单位和时间精度。使用`timesale命令可以在同一个设计里面包含采用了不同的时间单位模块。格式:

`timesale<时间单位>/<时间精度>(4)条件编译命令`ifdef、`else、`endif
参考技术B monitoron和monitoron和monitoroff任务的作用是通过打开和关闭监控标志来控制监控任务monitor的启动和停止,这样使得程序员可以很容易的控制monitor的启动和停止,这样使得程序员可以很容易的控制monitor何时发生。monitoron来启动monitoron来启动monitor时不管monitor参数列表中的值是否发生改变,总是立刻输出显示当前时刻参数列表中的值,这用于在监控的初始时刻设定初始比较值。在默认情况下,控制标志在仿真的起始时刻就已经打开了。在多模块调试的情况下,许多模块都调用了monitor参数列表中的值是否发生改变,总是立刻输出显示当前时刻参数列表中的值,这用于在监控的初始时刻设定初始比较值。在默认情况下,控制标志在仿真的起始时刻就已经打开了。在多模块调试的情况下,许多模块都调用了monitor,因为任何时刻只能用一个monitor起作用,因此需要配合monitor起作用,因此需要配合monitoron与monitoroff使用,把需要监视的模块用monitoroff使用,把需要监视的模块用monitor打开,在监视完毕后及时用monitoroff关闭,以便把monitoroff关闭,以便把monitor让给其它模块使用。

.NET 中的锁定(监视器)内部实现

【中文标题】.NET 中的锁定(监视器)内部实现【英文标题】:Lock (Monitor) internal implementation in .NET 【发布时间】:2011-07-03 23:08:01 【问题描述】:

要掌握某些技术,您必须知道它是如何在更低的抽象级别上实现的。在多线程编程的情况下,最好了解同步原语。 这是一个问题,如何在 .NET 中实现 Lock (Monitor)?

我对这些方面很感兴趣: - 它是否使用操作系统对象?; - 它需要用户模式还是内核模式?; - 等待锁定的线程的开销是多少?; - 在什么情况下,等待锁的线程队列可能会被违反?

更新: “如果多个线程争用锁,它们将在“就绪队列”中排队,并按照先到先得的原则授予锁。注意:Windows 和 CLR 行为中的细微差别意味着队列的公平性有时会被违反。”[C# 4.0 in a Nutshell, Joseph Albahari] 所以这就是我在最后一个关于“违反队列”的问题中要问的问题。

【问题讨论】:

不,用户,无论获取锁需要多长时间,都不知道“违规队列”是什么样的。试着提出一个更好的问题。 如果我没记错的话,它会尝试旋转一段时间,如果这不起作用,它会返回内核。因此,如果锁不被争用,它会相当便宜,但对于高锁争用,它可能会变得更加昂贵。 此行为看起来与 Windows 中的关键部分相同。这是否意味着关键部分在后台使用? 【参考方案1】:

Wikipedia article 很好地描述了“监视器”是什么,以及它的底层技术条件变量。

请注意,.NET Monitor 是条件变量的正确实现;大多数已发布的 CV 的 Win32 实现都是不正确的,即使是在通常有信誉的来源(如 Dobbs 博士)中找到的也是如此。这是因为简历cannot easily be built from the existing Win32 synchronization primitives。

.NET CV 实现不是仅仅在 Win32 原语上构建一个浅层(且不正确)的包装器,而是利用它位于 .NET 平台上的事实,实现自己的等待队列等。

【讨论】:

在 .NET 4.0 中它更加正确。如果在Monitor.Enter 之后出现异常,则有可能使锁保持“卡住”(参见***.com/questions/2837070/…) 如果您想在 Win32 中使用条件变量,请使用随 Windows V6 (Vista/2008) 引入的操作系统实现:msdn.microsoft.com/en-gb/library/ms682052(VS.85).aspx @Richard:感谢您的提示!我不知道他们在 Win32 级别引入了这个。 你的***链接没有回答任何问题,问题的最重要部分是内核与用户模式......那篇文章是另一个聪明的聪明点【参考方案2】:

经过一些调查,我找到了问题的答案。一般来说,CodeInChaos 和 Henk Holterman 是对的,但这里有一些细节。

当线程首先开始与其他线程竞争锁时,它会旋转等待循环一段时间以尝试获取锁。所有这些操作都在用户模式中执行。然后如果没有成功的操作系统内核对象Event 创建,线程切换到内核模式 并等待来自这个Event 的信号。

所以回答我的问题是: 1. 在更好的情况下不,但在更糟糕的情况下是(Event 对象在需要时懒惰地创建); 2. 一般在用户模式下工作,但如果线程竞争锁的时间过长,线程可以切换到内核模式(通过Win API非托管函数调用); 3. 从用户模式切换到内核模式的开销(约 1000 个 CPU 周期); 4. 微软声称它是像 FIFO 一样的“诚实”算法,但它不保证这一点。 (例如,如果来自“等待队列”的线程将被挂起,它将在恢复时移动到队列的末尾。)

【讨论】:

您能发布任何研究资料吗?那会很有帮助 我想看看1和2语句的详细解释。我想知道 .NET 何时决定在 Monitor 实现中进入内核模式 这在 Clr Via C# 中有详细讨论,Jeffrey Richter 称其为“混合锁”。在用户模式下,监视器旋转并与其他线程竞争(因为它们没有被阻塞),一旦它们被提升为内核模式锁,它们就会被阻塞,从而释放周期。

以上是关于为啥在多模块调试的情况下$monitor需要配合$monitoron和$monitoroff来工作的主要内容,如果未能解决你的问题,请参考以下文章

为啥我要在不调试的情况下开始调试构建?

为啥 Monitor.Wait() 和 Monitor.Pulse() 需要锁?

为啥在多线程应用程序 C++ 中没有发生同步

[日常] windows下使用vscode配合xebug调试php脚本

Linux下打开Android调试器DDMS的方法

设计模式 - 单例模式之多线程调试与破坏单例