用于执行多个线程的数据处理设备中的共享资源的制作方法

文档序号:12071186阅读:392来源:国知局
用于执行多个线程的数据处理设备中的共享资源的制作方法与工艺

本技术涉及数字处理领域。具体地,本技术研究在其中执行多个线程的数据处理设备和方法。



背景技术:

数据处理设备可执行多个线程。线程可以步调一致(lockstep)的方式进展。具体地,每一线程可维护它自身的程序计数器。系统本身可维护自身的通用程序计数器,以使得针对(程序计数器与通用程序计数器匹配的)线程执行由通用程序计数器所指示的指令。此类系统可称为例如单指令多线程(SIMT)系统。因此,在每一步骤处,针对多个线程中的至少一子集执行单个指令。一旦已针对线程的子集执行指令,可改变通用程序计数器来指示新的指令。在此类系统中可以优选地设定通用程序计数器以匹配由线程中的每个线程维护的程序计数器中的最小者。以此方式,可允许最落后的线程取得进展,并且从而追赶上具有更高的程序计数器的线程。此可引发线程进入收敛,即共享相同程序计数器值以使得可在尽可能多的线程上执行单个指令。

对此方案的修改涉及追踪每个线程的函数调用深度。具体地,每当线程做出函数调用时,此线程的函数调用深度计数器递增,且每当线程自函数调用返回时,此线程的函数调用深度计数器递减。当通用程序计数器要变化时,即它被设定为匹配首先具有最高函数调用深度计数器的线程的程序计数器,且其次(若存在多个这样的线程)匹配此集合中具有最低程序计数器值的一个或多个线程的程序计数器。换言之,仅考虑具有最高函数调用深度的全部线程间的程序计数器值。因此,这帮助防止在仅考虑程序计数器值情况下将会发生的性能问题或死锁情形。当线程的子集做出函数调用时,这可使得与那些线程关联的程序计数器显著增加,使得应在函数本身之后下一个执行的指令并不具有最低程序计数器值。通过基于函数调用深度选择用于执行的线程,即便该函数不具有最低程序计数器也可先处理该函数。

上述两种机制皆倾向于遭受死锁,其中待执行的代码包含要求独占访问的共享资源。举例而言,可在任何一个瞬时处由单个线程保持锁定,从而允许线程且仅此线程访问共享资源。

访问共享资源的线程可比不可访问共享资源的其余线程具有更高的程序计数器。因此,将能够执行其余线程,但将无法执行具有对共享资源的访问权的线程。由于另一线程具有对共享资源的访问权的同时其余线程将不能够访问共享资源,将发生死锁。然而,具有对共享资源的访问权的线程可能永远不被允许执行。因此,无线程取得任何进展且系统暂停。



技术实现要素:

根据本技术的一个方面,提供了一种被配置为执行多个线程的数据处理设备,所述数据处理设备包括:通用程序计数器,用于标识指令流中要针对所述多个线程的至少一子集执行的一个指令,其中所述子集中的每一线程具有相关联的、用于标识所述指令流中的一个指令的线程程序计数器;选择器,被配置为选择线程的所述子集中的选定线程并且将所述通用程序计数器设定为与所述选定线程相关联的线程程序计数器;以及处理器,被配置为针对线程的所述子集中包括所述选定线程的一个或多个线程执行由所述通用程序计数器标识的指令,其中线程的所述子集与至少一个锁定参数相关联,该至少一个锁定参数用于追踪线程的所述子集中的哪个线程具有对共享资源的独占访问;其中所述处理器被配置为响应于针对一线程执行的第一指令而修改所述至少一个锁定参数来指示此线程已经获得对所述共享资源的独占访问,并且响应于针对此线程执行的第二指令而修改与所述线程相关联的所述至少一个锁定参数来指示所述线程不再具有对所述共享资源的独占访问;并且其中所述选择器被配置为基于所述至少一个锁定参数选择所述选定线程。

根据本技术的另一方面,提供一种用于针对多个线程中的子集执行指令流的数据处理方法,其中所述子集中的每一线程具有相关联的、用于标识所述指令流中的一个指令的线程程序计数器,所述数据处理方法包括以下步骤:

选择线程的所述子集中的选定线程,并且将通用程序计数器设定为与所述选定线程相关联的线程程序计数器,其中所述通用程序计数器标识所述指令流中要针对线程的所述子集执行的一个指令;以及

针对线程的所述子集中包括所述选定线程的一个或多个线程执行由所述通用程序计数器所标识的指令,

其中线程的所述子集与至少一个锁定参数相关联,该至少一个锁定参数用于追踪线程的所述子集中的何者具有对共享资源的独占访问;

其中所述至少一个锁定参数响应于针对一线程执行的第一指令而被修改以指示此线程已经获得对所述共享资源的独占访问,并且响应于针对此线程执行的第二指令而被修改以指示所述线程不再具有对所述共享资源的独占访问;并且

其中所述选择器被配置为基于所述至少一个锁定参数选择所述选定线程。

根据另一方面,提供一种被配置为执行多个线程的数据处理设备,该数据处理设备包含:

通用程序计数器装置,用于标识指令流中要针对所述多个线程的至少一子集执行的一个指令,其中所述子集中的每一线程具有相关联的、用于标识所述指令流中的一个指令的线程程序计数器装置;

选择装置,用于选择线程的所述子集中的选定线程并且将所述通用程序计数器装置设定为与所述选定线程相关联的线程程序计数器装置;以及

处理器装置,用于针对线程的所述子集中包括所述选定线程的一个或多个线程执行由所述通用程序计数器装置标识的指令,

其中线程的所述子集与至少一个锁定参数相关联,该至少一个锁定参数用于追踪线程的所述子集中的哪个线程具有对共享资源的独占访问;

其中所述处理器装置用于响应于针对一线程执行的第一指令而修改所述至少一个锁定参数来指示此线程已经获得对所述共享资源的独占访问,并且响应于针对此线程执行的第二指令而修改与所述线程相关联的所述至少一个锁定参数来指示所述线程不再具有对所述共享资源的独占访问;并且

其中所述选择装置用于基于所述至少一个锁定参数选择所述选定线程。

附图说明

仅通过示例的方式,本技术的其它方面、特征、优点和示例实施例将参照附图进行描述,其中:

图1示出了根据一个实施例的数据处理设备;

图2示出了具有不同程序计数器值的多个不同线程的执行的示例;

图3示出了其中可在SIMT系统中发生死锁的代码;

图4示出了解释可如何防止图3的死锁的第二代码示例;

图5以流程图形式示出了SIMT系统的线程之间的选择可如何发生;

图6以流程图形式示出了执行线程的方法;

图7示出了针对线程的子集维护的状态数据的另一示例;

图8示出了第三代码示例;以及

图9是示出使用图7的状态数据选择线程程序计数器的方法的流程图。

具体实施方式

在一个示例中,线程的子集已与至少一个锁定参数关联以便追踪子集中的哪个线程具有对共享资源的独占访问。处理器可响应于线程所执行的第一指令来修改至少一个锁定参数,从而指示线程已经获得对此共享资源的独占访问。类似地,处理器可响应第二指令来修改至少一个锁定参数,从而指示线程不再具有对此共享资源的独占访问。在选择选定线程(其线程程序计数器被用作通用程序计数器的值)并从而确定针对线程的子集下一个将执行哪个指令的过程中,数据处理设备可考虑至少一个锁定参数。通过基于锁定参数选择通用程序计数器的值,控制在任何特定时刻处能够执行哪些线程且从而减少或防止死锁发生几率是可能的。

举例而言,当线程获得或已经获得对共享资源的独占访问时可执行第一指令,且当线程放弃或已经放弃对共享资源的访问权时可执行第二指令。

处理器可被配置为响应于锁定序列包含针对线程执行的至少一个锁定指令,向线程授权对共享资源的独占访问。锁定序列可包含涉及各种比较、加载及存储的众多不同指令。此序列内可以是最终设定共享资源的所有权的锁定指令。在一些示例中,锁定指令可使得具有对共享资源的独占访问的线程的标识被存储或记录。在其他示例中,锁定指令可仅设定已锁定资源的指示,无需明确标识哪个线程具有锁定的所有权。在一些情况中,锁定序列可未包含第一指令。换言之,引发线程获得对共享资源的独占访问的锁定序列可与第一指令分离,该第一指令向处理器指示线程已经获得对共享资源的独占访问。因此,代码可包含含有锁定指令的锁定序列,该锁定序列位于第一指令之前或之后。此方法可用于确保与不支持第一指令的旧式系统的后向兼容性。即使不支持第一指令,可仍由旧式系统正常处理锁定序列。一些示例可在第一指令之前执行锁定序列,使得线程先试图获得对共享资源的独占访问,且随后若成功,则因此通过执行第一指令更新锁定参数。其他示例可在锁定序列之前执行第一指令,使得第一指令有效用于在使用锁定序列实际实施锁定之前为线程请求锁定特权。在第二种情况中,对锁定序列的进展可取决于第一指令被成功执行,这可取决于另一线程是否已具有锁定。在其他实施例中,锁定序列包含第一指令。换言之,锁定序列向线程中的一者授权对共享资源的独占访问,且亦设定线程的锁定参数以指示线程具有对共享资源的独占访问。因此,存在实施锁定序列及第一指令的不同方式。

类似地,处理器可被配置为响应于包含针对线程执行的至少一个解锁指令的解锁序列放弃该线程对共享资源的独占访问。解锁序列可包含众多不同指令,例如包括比较、加载或存储,该等指令引发特定线程失去对共享资源的独占访问。可例如通过移除对资源的锁定或通过将独占访问传递至不同线程来放弃对资源的独占访问。在解锁序列内可以是解锁指令,该解锁指令用于清除哪个线程具有对共享资源的独占访问或指示特定线程不再具有对共享资源的访问权。换言之,解锁指令可用于设定或清除变量以指示特定线程不再具有对共享资源的独占访问。在一些实施例中,解锁序列未包含第二指令。换言之,解锁序列并不修改与线程关联的锁定参数以指示线程不再具有对此共享资源的独占访问。因此,在代码中执行解锁的一个或多个指令与代码中设定锁定参数以指示线程不再具有对共享资源的访问权的指令之间存在分隔。此针对上文所论述的后向兼容性原因而适用。可在解锁序列之后执行第二指令。在其他实施例中,解锁序列包含第二指令。

选择器可被配置为优先于由至少一个锁定参数指示为不具有对共享资源的独占访问的第二线程而选择由至少一个锁定参数指示为具有对共享资源的独占访问的第一线程来作为选定线程。换言之,选择器可被配置为使得具有对共享资源独占访问的线程优先。因此,此线程能够完成它对共享资源的使用以便解锁共享资源。此帮助防止死锁,因为容许执行有能力解锁共享资源的第一线程并从而解锁共享资源。

选择器可被配置为基于与线程的子集中的每一线程关联的函数调用深度参数选择选定线程。换言之,当确定应使用哪个线程的线程程序计数器来设定通用程序计数器时,选择器可考虑函数深度调用参数及至少一个锁定参数两者。

选择器可被配置为基于与线程的子集中的每一线程关联的线程程序计数器选择选定线程。换言之,当确定应使用哪个线程程序计数器来设定为通用程序计数器时,选择器可考虑线程程序计数器及至少一个锁定参数两者。

可以不同方式实施对选定线程的选择。在一些示例中,可直接选择线程,且随后此线程的线程程序计数器可用于通用程序计数器。在其他示例中,可使用给定程序计数器选择算法选择特定线程程序计数器(隐含选择相应线程作为选定线程)。因此,大体而言,在本申请案中提及的选择选定线程意欲包含选择与线程关联的线程程序计数器之意。

锁定参数可采用众多不同形式。在一个示例中,子集内的每一线程可具有相应锁定参数。当获得对共享资源的独占访问的线程执行第一指令时,可修改此线程的锁定参数以指示线程已经获得对资源的独占访问。类似地,当线程放弃对线程的独占访问时,可响应于针对此线程执行的第二指令而修改相应锁定参数以指示线程不再具有对共享资源的独占访问。举例而言,每一线程的锁定参数可指示多少共享资源当前被此线程锁定。在此情况中,处理器可在某一时间处容许多个线程具有对不同共享资源的独占访问。当选择选定线程时,选择器可考虑线程的锁定参数以便选择第一组线程(例如,选择具有指示锁定资源的最高数目的锁定参数的线程),且随后基于函数调用深度在第一组线程中选择第二组线程,且随后基于与第二组线程中的线程关联的线程程序计数器选择第二组线程中的一者作为选定线程。此方法提供改良的性能,因为这使得多个线程同时对不同资源保持锁定是可能的,使得它们都可彼此并行行进。

换言之,选择器可被配置为首先考虑线程的锁定参数,随后考虑函数调用深度并最后考虑程序计数器。通过以此次序考虑参数,可能使得在特定时刻执行来自最适宜线程的指令。应注意,可无需选择器执行对第一组或第二组的选择。举例而言,若仅单个线程具有期望的锁定参数,则此线程的线程程序计数器将用于设定通用程序计数器。类似地,若第一组线程包含两个线程及这两个线程中的仅一者具有期望的函数调用深度,则可能不具体形成第二组线程,而是替代地,可将第一组线程中具有期望的函数调用深度的线程的线程程序计数器设定为通用程序计数器。换言之,尽管选择器可被配置为执行前文所论及的三个选择,但可能不必始终在每个情况中实施三个选择。

在另一示例中,至少一个锁定参数可包含在线程的子集之间共享的共享锁定参数,及指示线程的子集中的何者具有对共享资源的独占访问的锁定所有者参数。在一些情况中,共享锁定参数可包含锁定计数,该锁定计数指示由锁定所有者参数所指示的锁定自有线程具有对多少资源的独占访问。在其他情况中,共享锁定参数可包含锁定旗标,该锁定旗标指示当前线程的子集中的任何一者是否具有对共享资源的独占访问。在此示例中,处理器可确保在某一时间处线程的每个子集中仅一个线程被允许具有对共享资源的独占访问。因此,若一个线程具有对第一共享资源的独占访问,则不允许第二线程对第二共享资源的独占访问(甚至当第二共享资源与第一共享资源不同时亦如此)。此方法提供针对在存在递归锁定时可出现的死锁的增加保护,在递归锁定中不同线程逐步锁定一系列资源且随后依次释放锁定。若已知待执行的代码不能包括此类递归锁定,则每一线程具有相应锁定参数的前述方法可以是优选的以提升性能(且前述方法与现有技术相比仍大大减少了死锁发生)。然而,若需要递归锁定,则每次将锁定限制于一个线程可提供针对死锁的增加保护。在此情况中,不必为每一线程提供锁定参数,因为每次仅一个线程可持有锁定。替代地,指示哪个线程当前持有锁定的锁定所有者参数线程及在线程的子集之间共享的锁定参数(例如,指示由锁定自有线程持有的线程数目的锁定计数)足以追踪哪个线程持有锁定,使得程序计数器的选择可倾向于选择持有锁定的线程而非其他线程以避免死锁并确保向前进展。锁定计数用于确保在允许其他线程持有锁定之前再次放弃已由线程设定的全部锁定。

在第二示例中,若至少一个锁定参数指示线程具有对一个或多个共享资源的独占访问,则选择器可选择由锁定参数所指示的锁定自有线程作为选定线程,使得锁定自有线程可取得进展,使得最终该线程将释放锁定而另一线程可接着获得锁定。另一方面,若无线程持有锁定,则对选定线程的选择可基于函数调用深度及线程的线程程序计数器,如第一示例中所述。

在上文所论述的两个示例中,至少一个锁定参数可响应于第一指令递增及响应于第二指令递减(无论锁定参数是线程的子集之间共享的,还是特定于单个线程的)。在一个示例中,锁定参数可仅具有两个状态:第一状态,指示线程具有对共享资源的独占访问,及第二状态,指示线程不具有对共享资源的独占访问。此参数易于表示,因为这要求每个线程仅需要单个位。因此,需要非常小的空间且因此非常小的能量来表示每一线程的状态。在其他实施例中,锁定参数可指示线程具有独占访问的共享资源的数目。换言之,锁定参数可充当计数器,该计数器在线程获得对共享资源的独占访问时递增且在线程失去对共享资源的独占访问时递减。此系统为每一线程提供更好的优先级指示符。具体地,可能想要使具有对若干共享资源的独占访问的线程优先于具有对仅一个共享资源的独占访问的线程。然而,存储此额外信息需要更多空间,且因此必须为系统中待执行的每一线程投入更多能量。

由处理器执行的线程的子集中的一个或多个可包含具有与选定线程的相应线程参数相匹配的一个或多个线程参数的线程。在一个示例中,一个或多个线程参数可仅包含线程程序计数器。因此,所执行的一个或多个线程可以是其线程程序计数器标识由通用程序计数器标识的相同指令的线程。换言之,数据处理设备可执行其程序计数器与通用程序计数器相同的所有那些线程。或者,除了线程程序计数器之外,线程参数亦可包括函数调用深度参数或锁定参数中的一者或两者,使得针对具有匹配选定线程的线程参数的线程参数组合的线程执行指令。以此方式,可同时针对多个线程执行单个指令。

由数据处理设备的处理器执行的指令可以是微操作。在一些系统中,在到达处理器之前,复杂指令(例如,多重加载/存储指令)可被分成微操作。因此,应将本申请中对“指令”的引用解读为指示指令或者对应于指令之一部分的微操作。

可在至少一个预定义指令集中将第一指令及第二指令编码为NOOP(无操作)指令。在此情况中,数据处理设备所使用的指令集为预定义指令集的增强版本。换言之,数据处理设备所使用的指令集可定义未在预定义指令集中定义的指令。作为在至少一个预定义指令集中将第一指令及第二指令编码为NOOP指令的结果,在那些预定义指令集中可不考虑第一指令及第二指令。由于第一指令及第二指令将简单地对第二数据处理设备无效,经写入以在数据处理设备上操作的代码仍在实施预定义指令集的第二数据处理设备上正确执行。因此,为数据处理设备写入的代码可视为与旧式系统后向兼容。此意味着不必针对不同系统编码不同版本的代码,使得代码开发更有效率。

处理器可被配置为响应于第一指令及第二指令中的至少一者来执行另一操作。举例而言,另一操作可为以下各项中的一者或多者:作为锁定序列的一部分且用于获得对共享资源的独占访问的操作;作为解锁序列的一部分且用于放弃对共享资源的独占访问的操作;用于访问共享资源的操作;用于决定线程是否具有对共享资源的独占访问的操作;以及比较与交换操作。此允许利用另一指令覆盖更新线程的锁定参数的功能以减少需要执行的指令数目。

共享资源可包含存储器中的数据。共享资源的其他示例可为硬件装置、信道、或关键代码区段。

处理器可被配置为在放弃对共享资源的独占访问之前向存储器发出存储器屏障操作。存储器系统可以与自处理器接收到事务的次序不同的次序处理事务。可由处理器发布存储器屏障操作以控制存储器可重新排序事务的程度。存储器系统对存储器操作的重新排序被禁止跨越存储器屏障。亦即,尽管存储器能够自由地以任何次序处理连续的存储器屏障操作之间的操作,但当接收存储器屏障操作时,存储器应当先于在存储器屏障操作之后所接收的存储器操作而处理在存储器屏障操作之前所接收的全部存储器操作。若没有发布存储器屏障,则存在以下风险:在放弃对资源的独占访问之后所发布的事务在独占访问仍然被持有的同时被存储器处理,这可导致不正确的数据值。通过在放弃对共享资源的独占访问之前发布存储器屏障操作,系统可确保每次仅由单个线程访问共享资源且确保存储器中的数据一致性。

图1示出根据一个实施例的数据处理设备100。由选择器110将通用程序计数器120设定为与特定线程关联的程序计数器184中的一者。随后将通用程序计数器120的值发送至提取单元130,该提取单元提取由通用程序计数器120所指示的指令。将所提取的指令传递至译码指令的译码单元140,且将所译码的指令发送至发布单元150。发布单元150发布一个或多个信号至处理器160,以便针对线程中的一者或多者执行所提取的指令。处理器160可能够同时或实质上同时针对一个或多个线程执行指令。在一些实施例中,处理器160可具有用于处理每一相应线程的并行功能单元使得针对多个线程并行执行相同指令。其他系统可仅具有单个功能单元,使得在移动到下一指令之前针对线程的子集中的各者依次处理相同指令。其他系统可具有一些并行单元,但比线程的总数少,使得针对众多线程以小于线程总数的批量处理相同指令。

处理器160亦可访问存储器170,该存储器可包含高速缓存以及主存储器。处理器亦可与可在其中加载或存储数据值的寄存器文件180通信。在此实施例中,寄存器文件180包含针对每一线程的众多不同硬件单元。举例而言,图1中所示的寄存器文件180针对每一线程包含一组寄存器182、程序计数器184、函数调用深度计数器186及锁定计数器188。应了解,与图1所示不同的硬件配置可为可能的。举例而言,单个寄存器组182可包含一个以上线程的寄存器。此外,所示硬件组件的子集可存在于寄存器文件180外部。

在本文所描述的实施例中,仅考虑单组线程,其中并行执行那些线程的至少一子集。然而,应了解,数据处理设备100不限于此配置。举例而言,数据处理设备100可对线程的多个群组或子集执行,其中能够实质上同时执行线程的每一群组。因此,通用程序计数器120可包含一组通用程序计数器,组内的每一通用程序计数器与线程的不同群组相关。此说明书的其余部分仅考虑线程的单个群组(子集),但应了解,当存在多个线程群组时,可将所描述的技术应用于每一不同线程群组。

图2示出执行指令序列的线程T#0至T#31的单个群组。由于线程中的各者具有自身的寄存器且由于正受执行的指令参考寄存器,线程中的各者可在执行相同指令时不同地表现。指令0引发寄存器5及寄存器3中保持的数据值得以相加在一起并存储于寄存器0中。若先前加法等于0,则第1行上的指令引发线程的执行跳越至第3行处的“卷标(label)”。在此情况中,由线程T#2执行的加法结果(0+0)及由线程T#4执行的加法结果(-1+1)两者皆等于0,且因此对该等两个线程的控制流程跳越至“卷标”。其他线程并不跳越,反而继续第2行处的指令。

因此,线程T#2及T#4的程序计数器等于3并且其余线程的程序计数器等于2。为了促成线程的收敛,将数据处理设备100的通用程序计数器120设定为全部线程中的最低线程程序计数器184(亦即,2)。通过以此方式选择通用程序计数器120的值,可使得较不前进的线程取得进展,且因此追赶上其他线程,从而导致线程的收敛。此为所处的理想状态,因为随后系统的并行性被改善,亦即将并行执行更多线程。因此,将通用程序计数器120设定为值2,该值为与任何线程关联的最低程序计数器值。由于线程T#2及T#4不具有等于2的线程程序计数器,并未针对线程T#2及T#4执行第2行处的指令。其余线程执行第2行处的指令,从而引发寄存器0及寄存器4处的数据值彼此相乘,并存储于寄存器6中。已执行乘法,执行指令的线程中的各者的线程程序计数器前进到3。因此,全部线程具有相同程序计数器及实现收敛。第3行处的“指令”仅为卷标,且因此执行行进至第4行。此指令使得从主存储器中访问存储于寄存器9中的存储器地址并且此地址处的数据值被存储在寄存器8处。如图2所示,由于线程中的各者在寄存器9中存储不同存储器地址值(例如,线程T#0存储存储器地址100,而线程T#5存储存储器地址200),线程中的各者将存取不同存储器地址且因此在它们各自的寄存器8中存储不同值。可能将靶向相同高速缓存线或存储器的相同页的存储器访问合并成单个存储器访问,以节省功率及时间。

图3示出在两个线程上执行的代码,其中代码包含共享资源,经由锁定控制对该共享资源的访问权。此处,通过第7行与第9行之间的关键代码区段访问共享资源。共享资源可为关键代码区段所需要且每次一个线程需要对该资源独占访问的任何东西。举例而言,资源可为共享数据结构或硬件单元或装置的使用。或者,可将关键代码区段本身视为共享资源。在此示例中,选择器110被配置为将通用程序计数器120设定为具有最高函数调用深度计数器186的线程的线程程序计数器184。在多个线程具有最高函数调用深度计数器186的情况下,将通用程序计数器120设定为在具有最高函数调用深度计数器186的线程间的最低程序计数器184。如先前所论述,在正常情况下,需要允许优先于具有较高程序计数器值的线程而执行具有最低程序计数器的线程,以便引发线程的收敛发生。然而,如将所示,当存在关键代码区段时,此程序计数器选择机制引发死锁发生。

图3的若干指令指示寄存器x19中的地址。此地址可对应于一数据值,该数据值指示共享资源是否被线程锁定用于独占访问。在此示例中,当寄存器所指示之地址处的值为0时,则此指示未对第7行至第9行处的关键代码区段所使用的资源设定锁定,且当此地址处的值为1,则已设定锁定。然而,应了解,存在表示是否已授权对资源的独占访问的其他方式。应注意,当线程执行此代码示例时,执行第2行及第5行处的指令的不同线程可访问各自寄存器组182中的寄存器x19的不同版本,这可含有不同存储器地址。因此,线程设法访问的共享资源可在线程之间不同。另一方面,若存在寄存器x19含有相同地址的多个线程,则存在下文所论述的潜在冲突。

最初,全部线程将步调一致地执行。第0行包含卷标且因此对执行无效。第1行引发在寄存器w1中存储数据值1。第2行处的指令被称为加载独占指令。此引发访问数据值及设定监视器。监视器侦测是否修改数据值。因此,在此示例中,寄存器x19中指示的存储器地址中存储的数据值被访问,并被存储在寄存器w0中,且针对此存储器地址设定监视器。在第3行处,寄存器w0中所存储的数据值与数字0相比较。换言之,除了设定监视器以外,第2行及第3行集体决定寄存器x19中所指示的存储器地址中所存储的数据值是否等于0。若数据值不相等,则第4行处的指令引发执行跳越至第0行处的卷标retry_lock。换言之,若存储于寄存器w0中的数据值不等于0(亦即,另一线程已对共享资源具有锁定),则控制流程返回至卷标retry_lock,否则控制流程继续第5行。因此,第2行至第4行处的指令检查在执行第2行处的加载指令时另一线程是否已具有锁定。

另一方面,第5行至第6行处的指令检查另一线程是否已在执行第2行处的独占加载指令之后但在开始关键代码区段之前的某点处获得锁定。此确保多个线程无法同时获得锁定。第5行为存储独占指令,该指令使得仅在先前设定的监视器指示正被监视的存储器地址尚未被修改的时候存储数据值。在此示例中,该指令使得:仅在由寄存器x19所指示的存储器地址中存储的数据值尚未被修改的时候(因为监视器由第2行上的加载独占指令建立)才将寄存器w1中所存储的数据值(亦即,1)存储在寄存器x19所指示的存储器位置中。随后在寄存器w2处存储该存储成功与否的结果。具体地,若存储成功,则在w2中存储值0。否则,若存储不成功,则在w2存储非零值。当然,本领域技术人员应了解,用于指示成功或失败的具体数字并非重要,而且可易于对调这些数字。因为若另一线程尚未修改寄存器x19所指示的地址中所存储的数据值,才实施存储操作,所以若寄存器x19的值对于全部线程相同,则恰好一个线程将修改数据值。若不同线程需要不同锁定的资源,则可在不同线程的寄存器x19中置放不同地址,使得一个以上线程成功执行第5行处的存储指令是可能的。针对每一线程的存储独占指令的结果因此表现出此线程是否已获取锁定。在第6行处,实行比较以决定寄存器w2中所存储的数据值是否为0(亦即,存储独占指令是否不成功)。若w2处所存储的数据值不为0,则控制流程返回至第0行上的卷标retry_lock。否则,流程继续在第7行上。

第7行至第9行(图3中未图示)表示关键区段。亦即,鉴于先前锁定序列,每次仅可由每个共享资源单个线程执行关键区段(若使用不同资源,则多个线程可执行关键区段)。在需要相同资源的另一线程可进入之前,线程必须完成关键区段中的执行代码。关键区段可包括:利用共享资源的任何指令,诸如访问共享位置或共享数据结构的加载/存储指令,对于共享位置或共享数据结构需要独占访问以维护数据一致性;或利用每次仅可由一个线程使用的硬件装置的指令。

解锁序列被示出始于第10行。在已执行关键区段之后执行此代码。在第10行处,在寄存器w1中存储数据值0。在第11行处,将存储于寄存器w1中的数据值(亦即,0)存储在寄存器x19中所指示的存储器位置中,以指示此线程不再具有锁定。此意味着,到达第2行至第4行处的指令的另一线程现可成功获取锁定。

如前文所论及的,若多个线程试图获得相同锁定(亦即,在不同线程的寄存器组182中的寄存器x19的各个版本指示相同存储器位置),则用于向关键区段提供锁定的代码可引发在SIMT数据处理设备中发生死锁。举例而言,如图3所示,线程T#0可为获取对锁定的访问权且因此继续代码的第7行的线程。然而,线程T#1(及靶向相同资源的其他线程)将无法获取锁定。因此,在代码的第一次执行中,在无法获得锁定引发控制流程返回至第0行之前,除线程T#0以外的线程将执行直至代码的第6行。对于后续尝试,除线程T#0以外的线程将执行直至第4行,因为线程T#0现已将值#1存储至寄存器x19中所指示的地址。全部线程具有相同函数调用深度计数器值1。因此,选择器110将通用程序计数器120设定为与线程中的各者关联的最低线程程序计数器184。除线程T#0以外的全部线程具有程序计数器值0,且因此通用程序计数器值120将被设定为0。因此,将允许执行除线程T#0以外的线程。然而,那些线程将仍无法获取对关键区段的锁定,因为由T#0持有锁定。在第4行处,那些线程的控制流程将因此传到第0行。再次,当由选择器110对程序计数器值做出选择时,除线程T#0以外的线程具有程序计数器值(0),该程序计数器值比线程T#0的程序计数器值(7)低。因此,通用程序计数器值120将被设定为0且将允许执行除线程T#0以外的线程。此过程将继续,可能永远进行下去。仅线程T#0能够解锁对关键区段的访问权,且线程T#0仅可在已执行关键区段之后解锁对关键区段的访问权。然而,线程T#0无法执行关键区段,因为该线程的程序计数器值比其他线程的程序计数器值高,且因此决不将通用程序计数器120设定为与线程T#0关联的线程程序计数器。因此,在此示例中,发生死锁。无线程可取得任何进展且因此系统停滞。

图4示出对此死锁问题的解决方案。在此实施例中,为每一线程提供锁定计数器188,且选择器110被配置为除了函数调用深度及线程程序计数器之外基于锁定计数器选择选定线程(将该选定线程的线程程序计数器设定为通用程序计数器)。将通用程序计数器120设定为与具有最高锁定计数器188的线程关联的线程程序计数器184。若多个线程具有最高锁定计数器188,则在具有最高锁定计数器188的线程中考虑具有最高函数调用深度计数器186的线程。若多个线程具有最高锁定计数器188及最高函数调用深度计数器186,则在那些线程中选择具有最低程序计数器值的线程。随后基于选定线程的线程程序计数器更新通用程序计数器,且随后可针对具有匹配线程参数(至少匹配的线程程序计数器,且视情况还有匹配的函数调用深度及锁定参数)的任何线程执行由通用程序计数器所指示的指令。应了解,其他实施例可应用不同机制,其中直接选择特定线程程序计数器或者线程程序计数器、函数调用参数与锁定参数的特定组合(而非选择线程)。

图4的代码与图3的代码相同,其中在第6行及第12行处分别多了两个新指令。这些指令引发与线程关联的锁定计数器188条件性递增及递减。具体地,第6行上的指令“cond_inc_lock_count w2”在w2值为零情况下引发与线程关联的锁定计数器188递增。如参考图3所解释的,将w2值设定为0或者1,其中值0表示STXR指令成功(亦即,线程已成功获取锁定),而1表示STXR指令失败(亦即,线程无法获取锁定)。因此,若此线程已设法完成在第5行上的行进指令中获取锁定,第6行上的指令引发特定线程的锁定计数器188递增。第12行处的指令“dec_lock_count”使特定线程的锁定计数器188递减。此指令为无条件的。此原因在于每次仅通过单个线程(具体地,当前保持锁定且因此具有对关键区段的访问权的线程)执行第8行至第12行处的代码。因此,关于应使哪个线程的锁定计数器递减不存在歧义。

当代码执行时,作为第6行处的指令的结果,获取锁定的线程(T#0)使得它的锁定计数器递增。反之,其他线程并未使自身的锁定计数器递增,因为它们的寄存器值w2将为非零(未能获取锁定)。在第7行处,线程T#0将继续至第8行上,但其余线程将返回至第0行处的卷标“retry_lock”。如前文所解释,在此实施例中,选择器110被配置为将通用程序计数器120设定为具有最高锁定计数器的线程的程序计数器。因此,当线程T#0的程序计数器为8时,此线程将能够鉴于自身的较高锁定计数器188继续执行,即便是该线程的程序计数器182比其他线程的程序计数器更高。因此,线程T#0能够继续执行且将最终执行第10行至第11行上的解锁序列的代码,从而释放锁定。随后,线程T#0继续第12行,在该线处使线程的锁定计数器递减。在此点处,线程中的各者的锁定计数器等于0,线程中的各者的函数调用深度等于1,且因此,将通用程序计数器120设定为全部线程中的最低线程程序计数器184。因此,容许除线程T#0外的线程执行,且它们执行第0行与第7行之间的代码。在此执行期间,线程中的一者将获取锁定并如前文所描述使得该线程的锁定计数器188递增。此序列将重复,直至全部线程已通过关键代码区段。因此,尽管存在关键代码区段,但避免了死锁情形。

在图4的此示例中,cond_inc_lock_count及dec_lock_count指令仅影响与特定线程关联的锁定计数器188。然而,应了解,这些指令可执行额外操作。举例而言,条件性递增指令可与第5行上的独占存储指令或者第7行上的比较分支指令组合。在此情况中,在关于比较与分支指令的操作之前或并行地及在关于独占存储指令的操作之后实施条件性递增指令。类似地,递减锁定计数器指令可与其他操作组合。举例而言,递减锁定计数器指令可与在由寄存器x19指向的地址中存储数值0的指令组合。

亦存在实施锁定序列的众多方式。在图4的示例中,使用第2行上的加载独占指令与第5行上的存储独占指令的组合。实施锁定机制的另一方式可经由使用比较与交换指令(CMPXCHG)。比较与交换指令为原子基元。换言之,指令无法中断中间执行,而是替代地,一旦已开始,便执行至完成。比较与交换指令采用三个参数。参数中的一者为存储器中的位置。另一参数为比较值及又一参数为存储值。比较与交换指令测试存储器中的位置处的数据值是否等于比较值,且若是,则将存储值写入到存储器位置中且回传指示操作成功的结果。若存储器位置处的数据值不等于比较值,则没有东西被写入至存储器位置(存储器位置保留原始值),且结果反而指示操作不成功。再次,此比较与交换指令可与其他操作组合并可与cond_inc_lock_count指令组合。

可在dec_lock_count指令之前及关键代码区段之后执行存储器屏障操作。在数据处理设备中,可为了效率重新排序存储器存取指令。然而,不可跨存储器屏障发生此重新排序。因此,存储器屏障可帮助确保先于在已完成关键区段之后发布的存储器存取操作处理作为关键代码区段的一部分的存储器存取操作。

cond_inc_lock_count指令及dec_lock_count指令可各自经编码以使得在预定指令集中,cond_inc_lock_count指令及dec_lock_count指令的编码对应于NOOP指令。举例而言,数据处理设备100所使用的指令集可为将这两个指令编码为NOOP指令的指令集的增强版本。因此,在除数据处理设备100以外的数据处理设备上,两个指令可能无效。因此,经设计用于数据处理设备100的代码可与其他数据处理设备后向兼容,且可与未使用SIMT的数据处理设备后向兼容。

图5示出了选择选定线程的方法,将该选定线程的线程程序计数器用作通用程序计数器120。方法从步骤s200处开始,其中将第一组及第二组两者皆设定为空组。在步骤s205处,从全部线程中选择下一线程。此步骤与步骤s210、s215及s220一起集体形成迭代通过全部线程的回路。在步骤s210处,确定步骤s205处所选定的线程的锁定参数(亦即,锁定计数器188)是否等于全部线程中的最高锁定参数。若此线程的锁定参数等于全部线程中的最高锁定参数,则流程行进至步骤s215,否则流程继续步骤s220。假定在步骤s210中,数据处理设备知晓全部线程中的最高锁定参数。若此信息并不易于取得,可通过首先迭代通过全部线程或通过保持自先前线程可见的最高锁定参数的运转计数且当遇到比先前最高锁定参数更高的锁定参数时删除已添加至第一组中的线程来确定。在步骤s215处,将选定线程添加至第一组,且流程随后行进至步骤s220。在步骤s220处,确定是否存在更多线程要迭代通过。若存在更多线程,则流程返回到步骤s205,在该步骤处选择下一线程。若不存在更多线程,则流程继续步骤s225。因此,在步骤s220结束时,第一组线程被确定,该组线程包含具有等于任何线程的较高锁定参数的锁定参数的线程。步骤s225确定在第一组中是否存在恰好一个条目。若在第一组中存在恰好一个条目,则流程继续步骤s230,在该步骤处将第一组中的项目被返回作为选定线程。亦即,将通用程序计数器120设定成与第一组中的唯一线程关联的线程程序计数器184。若在步骤s225处在第一组中不存在恰好一个条目,则流程继续步骤s235。总的来说,步骤s205至s230试图使线程程序计数器选择的确定基于全部线程的锁定计数参数。若线程中的一者具有比全部其他线程更高的锁定计数器参数,则此线程为选定线程且将通用程序计数器120设定为与具有较高锁定计数器参数188的线程对应的线程程序计数器184。否则,如下文所解释来实施线程的进一步收缩。

在步骤s235处,自第一组选择下一线程。步骤s235至s250集体形成迭代通过第一组中的全部线程的回路。在步骤s240处,确定所选线程的函数调用深度是否等于第一组中的全部线程中的最高函数调用深度。再次,假定确定第一组中的全部线程中的最高函数调用深度是可能的。可确定此信息的一种方式为先迭代通过第一组中的全部线程,或如上文所论述的藉由维护运转计数值。若在步骤s240处所选线程的函数调用深度等于第一组中的全部线程中的最高函数调用深度,则流程继续步骤s245。否则,流程继续步骤s250。在步骤s245处,将所选线程添加至第二组,且流程继续步骤s250。在步骤s250处,确定在第一组中是否存在更多线程得以迭代通过。若在第一组中存在更多线程,则流程返回至步骤s235以继续回路。否则,流程继续步骤s255,在该步骤处确定在第二组中是否存在恰好一个条目。若在步骤s255处在第二组中存在恰好一个条目,则流程继续步骤s260。在步骤s260处,将第二组中的单个条目返回作为选定线程。换言之,将通用程序计数器120设定成与第二组中的单个线程关联的线程程序计数器184。举例而言,若一个以上线程共享最高锁定计数器参数188,但若那些线程中的仅一者具有最高函数调用深度计数器186,则可出现此情形。因此,通过将通用程序计数器120设定成与此线程关联的线程程序计数器184来允许执行此线程。集体而言,步骤s235至s260与用于确定通用程序计数器120的第二标准相关。

若在第二组中不存在恰好一个条目,则流程行进至步骤s265,在该步骤处将第二组中具有最低程序计数器184的条目返回作为选定线程。换言之,将通用程序计数器120设定成第二组中的全部线程中的线程程序计数器184中的最低者。因此,步骤s265提供第三标准以决定通用程序计数器120。

图6示出如何选择每一循环中执行的线程。在步骤s400处,基于锁定参数(锁定计数器)188、函数调用深度计数器186及线程程序计数器184选择多个线程中的一者(或等效地,对应于线程的线程程序计数器中的一者)。关于图5示出此过程的示例。在步骤s410处,将通用程序计数器120设定为选定线程的线程程序计数器。换言之,通用程序计数器120经设定以匹配与步骤s400中所选定的线程对应的线程程序计数器184。最后,在步骤s420处,针对所关联的线程参数匹配选定线程的线程参数的全部线程执行由通用程序计数器120所标识的指令(线程参数可仅包含线程程序计数器184,或可包含线程程序计数器与锁定计数器188及函数调用深度186中的一者或两者的组合)。此过程可引发与每一线程关联的线程程序计数器184改变,且因此随后从步骤s400处开始重复该过程,从而引发确定不同通用程序计数器值120。

在关于图4所论述的示例中,处理器有利地尝试为扭曲中的全部线程获取锁定且随后基于哪些线程能够获取锁定来对执行偏好次序进行分类。

参考图7至图9描述第二实施例。在此实施例中,每次允许群组中的仅一个线程保持锁定。再者,尽管在图4中处理器有利地尝试使用包括STXR指令的锁定序列为全部线程获取锁定,且随后仅在成功时使锁定计数递增以发出信号指示线程获得锁定特权,但是在图7至图9中翻转次序,使得首先执行指令以请求锁定特权并因此更新锁定参数。在此点处,处理器确保仅一个线程可成功执行请求锁定特权的指令(对于其他线程,这个指令的执行失效,且因此此线程的线程程序计数器并未递增)。已获得锁定特权,成功的线程随后执行锁定序列以获得锁定。以此方式,在任何时间点处允许群组中的仅一个线程保持锁定。解锁序列仍与图4相同,首先释放锁定,随后释放锁定特权。单个线程在持有锁定特权的同时可多次请求锁定,且可使用锁定计数器追踪由线程所保持的锁定数目。尽管可能用与第一实施例相同的方式实施第二实施例,其中每个线程具有锁定计数器并具有偏好较高锁定计数的程序计数器选择机制,因为每次将锁定特权(执行偏好)给予每群组的单个线程,但是可通过以下方式来简化这一方案:为作为整体的群组存储该群组中的任何线程是否具有锁定特权的单个指示、此线程的标识、以及群组的单个锁定计数器。

因此,图7示出寄存器文件180及供此第二实施例使用的状态数据的示例。图7与图1的寄存器文件的不同在于并未向每一线程提供锁定计数器188。替代地,除了线程的群组的通用程序计数器120之外,在线程的群组之间共享众多锁定参数:

·锁定设定旗标500,指示群组中的任何线程是否已针对一个或多个共享资源锁定;

·锁定所有者参数502,指示群组中的哪个线程已锁定一个或多个共享资源;及

·锁定计数参数504,指示由锁定所有者参数502所指示的锁定自有线程已锁定多少资源。

在一些示例中,可省略锁定设定旗标500且替代地,可使用锁定所有者参数502或锁定计数参数504发出信号指示线程是否保持锁定。举例而言,若锁定计数参数504为零,则此可发出信号指示无线程保持锁定,且若锁定计数参数504具有非零值,则此可发出信号指示线程保持锁定。或者,锁定所有者参数502可在线程中的一者保持锁定的情况下具有对应于该线程的值,且在无线程保持锁定的情况下具有并未对应于线程中的任何者的值,因此可有效指示是否已设定任何锁定。然而,有时,提供指示是否已设定任何锁定的独立锁定设定旗标500可为有用的,例如原因在于锁定设定旗标500可包含单个位,检查该单个位比检查对应于锁定所有者参数502或锁定计数值504的多位值更快且更有能量效率。

图8示出了用于第二实施例的代码示例,如下:

第0行:表示锁定序列开始的卷标,该卷标并未引发处理器处的任何特定动作。

第1行:inc_lock_count为请求锁定特权(用于线程为资源设定一个或多个锁定的权利)的指令。仅可针对群组中的一个线程成功执行此指令。因此,在此指令之后,一个线程可行进至下一指令(其中使此线程的程序计数器递增至下一指令),而其他线程无法成功执行此指令(且因此它们的线程程序计数器保留在相同指令inc_lock_count处,直至可成功执行此指令)。若成功执行inc_lock_count,则设定锁定设定旗标500以指示线程保持锁定特权,设定锁定所有者参数502以指示当前线程的标识符,且使锁定计数504递增。

第2行:用于在具有锁定特权的线程无法获得锁定的情况下分支到的卷标retry_lock,。

第3行至第5行:与图4的第1行至第3行相同,用于检查另一进程(例如,线程的当前群组外部的线程,或例如在多处理器系统中的不同处理器上执行的进程)是否已获得由寄存器x19中的地址所标识的、针对资源的锁定。

第6行:条件性分支,在另一进程持有针对x19中所标识的地址的锁定的情况下分支至第10行至第12行处的“后退”序列。

第7行至第8行:与图4的第5行及第7行相同。针对寄存器x19中的地址设定锁定的存储独占指令,及条件性分支,若存储独占指令失效,则分支回到第2行。与图4的第6行不同,若成功获取锁定,则不存在条件性指令使锁定计数递增,因为在图8中,锁定计数已在第1行处递增。

第9行:若成功获取锁定,则分支至第13行以使用已锁定的资源进行操作。

第10行:卷标“backoff_lock”表示后退序列的开始,该后退序列用于在已设定由寄存器x19中的地址所标识的、针对资源的锁定的情况下放弃锁定特权。通过放弃锁定特权,可在其版本的寄存器x19中具有不同地址的另一线程可能能够成功获得自身的锁定,并取得进展。

第11行:使锁定计数504递减。若此导致锁定计数504变成零,则亦清除锁定设定旗标500,使得另一线程可获得锁定特权。在第11行之后,线程可等待一些时间以允许相同群组中的其他线程有时间完成使用锁定的处理及释放该锁定。

第12行:分支回到第0行处的锁定序列的开始以再次努力获得锁定。

第13行:卷标“lock_acquired”表示成功获取锁定情况下执行的序列开始。在此之后,可使用已锁定资源执行任何数目的指令。

第14行:一旦完成使用已锁定资源的处理,随后便开始解锁序列。

第15行至第17行:与图4的第10行至第12行相同以放弃锁定,只是在此情况中若执行dec_lock_count指令及此导致锁定计数504变成零,则对锁定设定旗标500清零。

因此,在此示例下,每次相同的线程群组内仅一个线程可保持锁定,以提供防止死锁的额外保护。

图9示出当使用第二实施例时选择选定线程(且因此将哪个线程程序计数器设定为线程群组的通用程序计数器)的方法。由于群组内每次仅一个线程可保持锁定,程序计数器选择过程的初始部分变得更简单。在步骤600处,选择器110确定锁定设定旗标500是否指示群组内的任何线程是否持有锁定。若是,则在步骤602处,选择器110选择由锁定所有者参数502所指示的线程作为选定线程。

另一方面,若锁定设定旗标500指示群组中无线程当前持有锁定,则在步骤604处,将群组(子集)中的全部线程视为线程的“第一组”中的一部分。方法随后行进至图5的步骤S225,且之后,方法随后以与图5相同的方式行进,以基于函数调用深度及线程程序计数器选择选定线程。

已选择选定线程,可如前所述应用图6的步骤S410及S420。

在本申请中,词语“被配置为…”被用于表示设备中的元件具有能够执行定义的操作的配置。在此上下文中,“配置”意味着硬件或软件的互连的布置或方式。例如,设备可具有提供所定义的操作的专用硬件,或者处理器或其它处理装置可被编程以执行功能。“被配置为”并不暗示设备元件需要以任何方式被改变从而提供所定义的操作。

尽管本文已参照附图详细描述本技术的说明性实施例,但要理解,本技术不限于那些精确实施例,且本领域技术人员可在不脱离由所附权利要求定义的技术的范围和精神的情况下实行各种变化、添加及修改。举例而言,可在不脱离本技术的范畴的情况下利用独立权利要求的特征进行从属权利要求的特征的各种组合。

当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1