CRI ADX  Last Updated: 2024-07-17 10:48 p
关于线程

线程框架

CRI Atom运行时库使用线程系统,以便能够与应用程序并行有效地执行文件读取和音频数据播放处理。
CRI Atom运行时库按照“线程框架”运行,可以根据应用程序的请求指定线程框架的类型“线程模型”

线程模型有三种类型。
在运行时库初始化的配置结构体( CriAtomExConfig )的 thread_model成员中指定线程模型。

线程框架的类型

线程模型 说明 初始化常数
多线程框架(定时器驱动型) 用运行时库创建线程 CRIATOMEX_THREAD_MODEL_MULTI
多线程框架(用户驱动型) 用运行时库创建线程 CRIATOMEX_THREAD_MODEL_MULTI_USER_DRIVEN
用户多线程框架 用应用程序创建线程 CRIATOMEX_THREAD_MODEL_USER_MULTI
单线程框架 未使用线程 CRIATOMEX_THREAD_MODEL_SINGLE



在任何线程模型中,如想要正确运行框架,“定期执行Server处理函数”非常重要。

多线程框架

如果在初始化处理时选择多线程框架(定时器驱动型),则运行时库在内部创建线程,在线程上执行音频数据的解码和文件访问。
CRI Atom线程优先级预设为THREAD_PRIORITY_HIGHEST。
根据不同线程驱动方法,多线程框架可进一步分为以下两种类型。
  • 定时器驱动型
  • 用户驱动型

关于定时器驱动型

定时器驱动时,Atom运行时库定期启动线程,执行Server处理。
多线程框架(定时器驱动型)的概念
注意
即使在选择定时器驱动型的情况下,作为Server处理函数,也必须定期执行::criAtomEx_ExecuteMain 函数。
(所有耗时的处理,有如解码处理和等待文件访问完成等都在运行时库创建的线程上执行,同时也可能会执行几个极短时间即可结束的处理。)

关于用户驱动型

用户驱动时,在用户执行::criAtomEx_ExecuteMain 函数时启动线程,执行Server处理。
多线程框架(用户驱动型)的概念

用户多线程框架

如果在初始化处理时选择用户多线程框架,则运行时库不会创建线程。
但是,为了在从多个线程同时执行Server处理的情况下也能正常运行,独占控制对共享资源的访问。
使用用户多线程框架时,作为Server处理函数,必须定期执行::criAtomEx_ExecuteAudioProcess 函数。
与多线程模式时的::criAtomEx_ExecuteMain 函数不同,将在调用的线程上执行Server处理。
  • criAtomEx_ExecuteAudioProcess 函数仅执行音频播放处理。
  • 应用程序必须调用::criFs_ExecuteFileAccess 函数来进行文件访问处理。
    (如果要读取压缩数据,则还需要调用::criFs_ExecuteDataDecompression 函数。)
  • criAtomEx_ExecuteAudioProcess 函数执行1V处理后结束, ::criFs_ExecuteFileAccess 函数和::criFs_ExecuteDataDecompression 函数的处理时间则因数据大小而异。
    请注意:在主线程中调用::criFs_ExecuteFileAccess 函数和::criFs_ExecuteDataDecompression 函数时,有可能会发生丢帧或声音中断。
用户多线程框架的概念
注意
如果在用户多线程框架时执行串流播放,请不要执行::criAtomEx_ExecuteMain 函数。
( 由于在::criAtomEx_ExecuteMain 函数内要等待文件读取完成,因此在函数中某几个V的处理会被锁定。)
执行串流播放时,请在主线程上仅执行::criAtomEx_ExecuteAudioProcess 函数, 在其他线程上执行::criFs_ExecuteFileAccess 函数和::criFs_ExecuteDataDecompression 函数。

单线程框架

如果在初始化处理时选择单线程框架,则运行时库不会创建线程。
此外,由于不假定从多个线程同时执行Server处理,所以对共享资源的访问不会有排斥处理。
使用单线程框架时,作为Server处理函数,必须定期执行::criAtomEx_ExecuteMain 函数。
与多线程模式时的::criAtomEx_ExecuteMain 函数不同,将在调用的线程上执行Server处理。
(因为音频、文件访问、数据展开处理都在::criAtomEx_ExecuteMain 函数中执行,所以处理时间可能超过1V。)
单线程框架的概念
注意
如果在单线程框架时执行文件读取,则criAtomEx_ExecuteMain函数的处理时间在大多数情况下都会超过1V。
执行串流播放时将不使用单线程框架,请选择其他框架。

是否线程安全

每个模块的安全性

CRI Atom运行时库的函数能否做到线程安全因模块而异。
各模块支持多线程访问的情况如下。

支持多线程访问的情况

模块 是否线程安全 补充信息
CriAtomEx API 不安全 有一些特殊的线程安全函数(后述)
CriAtomExPlayer API 不安全 从多个线程同时访问一个句柄时会发生问题
CriAtomExVoicePool API 不安全 从多个线程同时访问一个句柄时会发生问题
CriAtomExAcb API 不安全 从多个线程同时访问一个句柄时会发生问题
CriAtomPlayer API 不安全 从多个线程同时访问一个句柄时会发生问题
CriAtomAwb API 不安全 从多个线程同时访问一个句柄时会发生问题
CriAtomHcaMx API 不安全 从多个线程同时访问一个句柄时会发生问题
CriAtomAsr API 不安全 从多个线程同时访问一个句柄时会发生问题
CriErr API 不安全


使用多个句柄时

即使在调用不安全的API时,如果每个线程使用不同的句柄,则可以同时执行相同的函数。
例如,虽然 criAtomExPlayer_SetCueId 函数不安全,但可以为每个线程创建不同的 CriAtomExPlayerHn 句柄,并调用 criAtomExPlayer_SetCueId 函数。

具体示例包括以下情况。
void thread_func1(void)
{
CriAtomExPlayerStatus player_status;
player_1 = criAtomExPlayer_Create(&player_config, NULL, 0);
criAtomExPlayer_SetCueId(player_1, acb_hn, CRIATOMEX_CUE_BOMB2);
for (;;) {
player_status = criAtomExPlayer_GetStatus(player_1);
if (player_status == CRIATOMEXPLAYER_STATUS_PLAYEND) {
break;
}
sleep(10);
}
}
void thread_func2(void)
{
CriAtomExPlayerStatus player_status;
player_2 = criAtomExPlayer_Create(&player_config, NULL, 0);
criAtomExPlayer_SetCueId(player_2, acb_hn, CRIATOMEX_CUE_THUNDER3);
for (;;) {
player_status = criAtomExPlayer_GetStatus(player_2);
if (player_status == CRIATOMEXPLAYER_STATUS_PLAYEND) {
break;
}
sleep(10);
}
}
void criAtomExPlayer_Destroy(CriAtomExPlayerHn player)
Destroy an AtomEx player
void criAtomEx_ExecuteMain(void)
Execute the server processing
CriAtomExPlayerStatus criAtomExPlayer_GetStatus(CriAtomExPlayerHn player)
Get the player status
CriAtomExPlayerHn criAtomExPlayer_Create(const CriAtomExPlayerConfig *config, void *work, CriSint32 work_size)
Create an AtomEx player
void criAtomExPlayer_SetCueId(CriAtomExPlayerHn player, CriAtomExAcbHn acb_hn, CriAtomExCueId id)
Set the sound data to play (specifying a Cue ID)
enum CriAtomExPlayerStatusTag CriAtomExPlayerStatus
Player status
@ CRIATOMEXPLAYER_STATUS_PLAYEND
Definition: cri_le_atom_ex.h:3670



上述代码中,可以同时执行thread_func1和thread_func2两个线程。

特殊的线程安全函数

即使模块本身不是线程安全,作为特殊情况,以下函数也可以做到线程安全。

这些函数可以与同一模块的其他函数同时执行。

关于资源释放的注意事项

运行时库的结束处理( criAtomEx_Finalize 函数)和丢弃句柄的函数( criAtomExPlayer_Destroy 函数等)都会释放所有的库(句柄)资源。
因此,即使在执行线程安全函数期间,如果其他线程执行这些函数,也有可能引起访问冲突等严重问题。