0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

整體thread模型的設(shè)計(jì)與實(shí)現(xiàn)

FPGA之家 ? 來源:CSDN ? 作者:周嘉祺 ? 2021-03-29 14:39 ? 次閱讀

SPDK Thread 模型是SPDK誕生以來十分重要的模塊,它的設(shè)計(jì)確保了spdk應(yīng)用的無鎖化編程模型,本文基于spdk最新的release 19.07版本介紹了整體thread模型的設(shè)計(jì)與實(shí)現(xiàn),并詳細(xì)分析了NVMe-oF的使用案例。

P1

SPDK Thread 模型設(shè)計(jì)與實(shí)現(xiàn)

Reactor – 單個(gè)CPU Core抽象,主要包含了:

Lcore對(duì)應(yīng)的CPU Core id

Threads在該核心下的線程

Events 這是一個(gè)spdk ring,用于事件傳遞接收

Thread – 線程,但它是spdk抽象出來的線程,主要包含了:

io_channels資源的抽象,可以是bdev,也可以是具體的tgt

tailq 線程隊(duì)列,用于連接下一個(gè)線程

name 線程的名稱

Stats 用于計(jì)時(shí)統(tǒng)計(jì)閑置和忙時(shí)時(shí)間的

active_pollers 輪詢使用的poller,非定時(shí)

timer_pollers 定時(shí)的poller

messages 這是一個(gè)spdk ring,用于消息傳遞接收

msg_cache 事件的緩存

1.1 Reactor

對(duì)象g_reactor_state有五個(gè)狀態(tài)對(duì)應(yīng)了應(yīng)用中reactors運(yùn)行運(yùn)行狀態(tài),

enum spdk_reactor_state {

SPDK_REACTOR_STATE_INVALID = 0,

SPDK_REACTOR_STATE_INITIALIZED = 1,

SPDK_REACTOR_STATE_RUNNING = 2,

SPDK_REACTOR_STATE_EXITING = 3,

SPDK_REACTOR_STATE_SHUTDOWN = 4,

};

初始情況下是:

SPDK_REACTOR_STATE_INVALID狀態(tài),在spdk app(任意一個(gè)target,比如nvmf_tgt)啟動(dòng)時(shí),即調(diào)用了spdk_app_start方法,會(huì)調(diào)用spdk_reactors_init,在這個(gè)方法中將會(huì)初始化所有需要被初始化的reactors(可以在配置文件中指定需要使用的Core,CPU Core 和reactor是一對(duì)一的)。并且會(huì)將g_reactor_state設(shè)置為SPDK_REACTOR_STATE_INITIALIZED。具體代碼如下:

Int spdk_reactors_init(void)

{

// 初始化所有的event mempool

g_spdk_event_mempool = spdk_mempool_create(…);

// 為g_reactors分配內(nèi)存,g_reactors是一個(gè)數(shù)組,管理了所有的reactors

posix_memalign((void **)&g_reactors, 64, (last_core + 1) * sizeof(struct spdk_reactor));

// 這里設(shè)置了reactor創(chuàng)建線程的方法,之后需要初始化線程的時(shí)候?qū)?huì)調(diào)用該方法

spdk_thread_lib_init(spdk_reactor_schedule_thread, sizeof(struct spdk_lw_thread));

// 對(duì)于每一個(gè)啟動(dòng)的reactor,將會(huì)初始化它們

// 初始化reactor過程,即為綁定lcore,初始化spdk ring、threads,對(duì)rusage無操作

SPDK_ENV_FOREACH_CORE(i) {

reactor = spdk_reactor_get(i);

spdk_reactor_construct(reactor, i);

}

// 設(shè)置好狀態(tài)返回

g_reactor_state = SPDK_REACTOR_STATE_INITIALIZED;

return 0;

}

在進(jìn)入SPDK_REACTOR_STATE_INITIALIZED狀態(tài)且spdk_app_start在創(chuàng)建了自己的線程并綁定到了reactors后,會(huì)調(diào)用spdk_reactors_start方法并將g_reactor_state設(shè)置為SPDK_REACTOR_STATE_RUNNING狀態(tài)并會(huì)創(chuàng)建所有reactor的線程且輪詢。

Void spdk_reactors_start(void) {

SPDK_ENV_FOREACH_CORE(i) {

if (i != current_core) { // 在非master reactor中

reactor = spdk_reactor_get(i); // 得到相應(yīng)的reactor

// 設(shè)置好線程創(chuàng)建后的一個(gè)消息,該消息為輪詢函數(shù)

rc = spdk_env_thread_launch_pinned(reactor-》lcore, _spdk_reactor_run, reactor);

// reactor創(chuàng)建好線程并且會(huì)自動(dòng)執(zhí)行第一個(gè)消息

spdk_thread_create(thread_name, tmp_cpumask);

}

}

// 當(dāng)前CPU core得到reactor,并且開始輪詢

reactor = spdk_reactor_get(current_core);

_spdk_reactor_run(reactor);

}

之前提到spdk_reactors_init方法中調(diào)用了spdk_thread_lib_init方法傳入了創(chuàng)建thread的spdk_reactor_schedule_thread方法,在調(diào)用spdk_thread_create會(huì)回調(diào)該方法。這個(gè)方法它主要的功能就是告訴這個(gè)新創(chuàng)建的線程綁定創(chuàng)建該線程的reactor。

spdk_reactor_schedule_thread(struct spdk_thread *thread)

{

// 得到該線程設(shè)置的cpu mask

cpumask = spdk_thread_get_cpumask(thread);

for (i = 0; i 《 spdk_env_get_core_count(); i++) {

…。 // 遍歷cpu core

// 通過cpu mask找到對(duì)應(yīng)的核心,并產(chǎn)生event

if (spdk_cpuset_get_cpu(cpumask, core)) {

evt = spdk_event_allocate(core, _schedule_thread, lw_thread, NULL);

break;

}

}

// 傳遞該event,即對(duì)應(yīng)的reatcor會(huì)調(diào)用_schedule_thread方法,

spdk_event_call(evt);

}

_schedule_thread(void *arg1, void *arg2)

{

struct spdk_lw_thread *lw_thread = arg1;

struct spdk_reactor *reactor;

// 消息傳遞到對(duì)應(yīng)的reactor后將該thread加入到reactor中

reactor = spdk_reactor_get(spdk_env_get_current_core());

TAILQ_INSERT_TAIL(&reactor-》threads, lw_thread, link);

}

在SPDK_REACTOR_STATE_RUNNING后,此時(shí)所有reactor就進(jìn)入了輪詢狀態(tài)。_spdk_reactor_run函數(shù)為線程提供了輪詢方法:

static int _spdk_reactor_run(void *arg) {

while (1) {

// 處理reactor上的event消息,消息會(huì)在之后講到

_spdk_event_queue_run_batch(reactor);

// 每一個(gè)reactor上注冊(cè)的thread進(jìn)行遍歷并且處理poller事件

TAILQ_FOREACH_SAFE(lw_thread, &reactor-》threads, link, tmp) {

rc = spdk_thread_poll(thread, 0, now);

}

// 檢查reactor的狀態(tài)

if (g_reactor_state != SPDK_REACTOR_STATE_RUNNING) {

break;

}

}

}

而當(dāng)spdk app被調(diào)用spdk_app_stop方法后將會(huì)相應(yīng)的通知每一個(gè)reactor調(diào)用spdk_reactors_stop方法,將g_reactor_state賦值為SPDK_REACTOR_STATE_EXITING,即開始退出了。回到_spdk_reactor_run函數(shù)中,輪詢將會(huì)被跳出,并且執(zhí)行銷毀線程的代碼。

static int _spdk_reactor_run(void *arg) {

…。. // 輪詢

TAILQ_FOREACH_SAFE(lw_thread, &reactor-》threads, link, tmp) {

thread = spdk_thread_get_from_ctx(lw_thread);

TAILQ_REMOVE(&reactor-》threads, lw_thread, link);

spdk_set_thread(thread);

spdk_thread_exit(thread);

spdk_thread_destroy(thread);

}

}

在這之后,主線程的_spdk_reactor_run會(huì)返回到spdk_reactors_start中,并將g_reactor_state賦值為SPDK_REACTOR_STATE_SHUTDOWN,返回到spdk_app_start中等待應(yīng)用退出。

最后,總結(jié)一下reactors和CPU core以及spdk thread關(guān)系應(yīng)該如圖1所示

fbdba11c-8ecb-11eb-8b86-12bb97331649.png

圖1 CPU cores、reactors和thread關(guān)系圖

Reactor生命周期流程圖則如圖2所示

fc609bb0-8ecb-11eb-8b86-12bb97331649.png

圖2 reactor生命周期流程圖

1.2 thread

當(dāng)Reactors進(jìn)行輪詢時(shí),除了處理自己的事件消息之外,還會(huì)調(diào)用注冊(cè)在該reactor下面的每一個(gè)線程進(jìn)行輪詢。不過通常一個(gè)reactor只有一個(gè)thread,在spdk應(yīng)用中,更多的是注冊(cè)多個(gè)poller而不是注冊(cè)多個(gè)thread。具體的輪詢方法為:

Int spdk_thread_poll(struct spdk_thread *thread, uint32_t max_msgs, uint64_t now) {

// 首先先處理ring傳遞過來的消息

msg_count = _spdk_msg_queue_run_batch(thread, max_msgs);

// 調(diào)用非定時(shí)poller中的方法

TAILQ_FOREACH_REVERSE_SAFE(poller, &thread-》active_pollers,

active_pollers_head, tailq, tmp) {

// 調(diào)用poller注冊(cè)的方法之前,會(huì)對(duì)poller狀態(tài)檢測且轉(zhuǎn)換

if (poller-》state == SPDK_POLLER_STATE_UNREGISTERED) {

TAILQ_REMOVE(&thread-》active_pollers, poller, tailq);

free(poller);

continue;

}

poller-》state = SPDK_POLLER_STATE_RUNNING;

// 調(diào)用poller注冊(cè)的方法

poller_rc = poller-》fn(poller-》arg);

// poller轉(zhuǎn)換狀態(tài)

poller-》state = SPDK_POLLER_STATE_WAITING;

}

// 調(diào)用定時(shí)poller中的方法

TAILQ_FOREACH_SAFE(poller, &thread-》timer_pollers, tailq, tmp) {

// 類似非定時(shí)poller過程,不過會(huì)檢查是否到了預(yù)定的時(shí)間

if (now 《 poller-》next_run_tick) break;

}

// 最后統(tǒng)計(jì)時(shí)間

}

Io_device 和 io_channel在thread中也是非常重要的概念。它們的實(shí)現(xiàn)都在thread.c中,io_device是設(shè)備的抽象,io_channel是對(duì)該設(shè)備通道的抽象。一個(gè)線程可以創(chuàng)建多個(gè)io_channel 。 io_channel只能和一個(gè)io_device綁定,并且這個(gè)io_channel是別的線程使用不了的。

fd1f8890-8ecb-11eb-8b86-12bb97331649.png

圖 3 io_device、io_channel和線程關(guān)系圖

Io_device結(jié)構(gòu)

struct io_device {

void *io_device; // 抽象的device指針

char name[SPDK_MAX_DEVICE_NAME_LEN + 1]; // 名字

spdk_io_channel_create_cb create_cb; // io_channel創(chuàng)建的回調(diào)函數(shù)

spdk_io_channel_destroy_cb destroy_cb; // io_channel銷毀的回調(diào)函數(shù)

spdk_io_device_unregister_cb unregister_cb; // io_device解綁的回調(diào)函數(shù)

struct spdk_thread *unregister_thread; // 不使用該device線程

uint32_t ctx_size; // ctx的大小,將會(huì)傳給io_channel處理

uint32_t for_each_count; // io_channel的數(shù)量

TAILQ_ENTRY(io_device) tailq; // device隊(duì)列頭

uint32_t refcnt; // 計(jì)數(shù)器

bool unregistered; // 是否該device被注冊(cè)

};

可以看到,io_device實(shí)際上只提供了一些自身io_device的操作和io_channel相關(guān)的方法,具體的io_device實(shí)體其實(shí)是那個(gè)名字叫io_device的void指針。因?yàn)閠hread中的io_device只提供了thread這一層接口,具體的io操作每一個(gè)設(shè)備很難被抽象出來,所以這一層的接口只負(fù)責(zé)管理io_channel的創(chuàng)建、銷毀和綁定等。

Io_channel的結(jié)構(gòu)

struct spdk_io_channel {

struct spdk_thread *thread; // 綁定的線程

struct io_device *dev; // 綁定的io_device

uint32_t ref; // io_channel引用計(jì)數(shù)

uint32_t destroy_ref; // destroy前被引用的次數(shù)

TAILQ_ENTRY(spdk_io_channel) tailq; // io_channel 隊(duì)列頭

spdk_io_channel_destroy_cb destroy_cb; // io_channel銷毀的回調(diào)函數(shù)

};

雖然io_channel看起來是很簡單的結(jié)構(gòu)體,實(shí)際上在創(chuàng)建一個(gè)io_device的時(shí)候,會(huì)要求使用者傳入一個(gè)io_channel_ctx的大小作為調(diào)用的參數(shù),而在給io_channel分配內(nèi)存的時(shí)候,除了分配本身io_channel結(jié)構(gòu)體的大小外,還會(huì)額外分配一個(gè)io_channel_ctx的大小,這個(gè)context可以理解成一個(gè)void指針,當(dāng)用戶在使用io_channel的時(shí)候,實(shí)際上還是通過context的部分去訪問io_device。

P2

NVMe-oF實(shí)例

nvmf_tgt 是spdk中一個(gè)重要的模塊,這里詳細(xì)的寫一下它作為一個(gè)target實(shí)例是如何使用thread、io_device以及io_channel的。

在spdk應(yīng)用剛啟動(dòng)的時(shí)候,reactor模塊就會(huì)自動(dòng)加載起來,然后在加載nvmf subsystem的時(shí)候,會(huì)調(diào)用spdk_nvmf_subsystem_init(lib/event/subsystems/nvmf/nvmf_tgt.c)方法,nvmf_tgt其實(shí)也是有生命周期,并且有一個(gè)狀態(tài)機(jī)去管理它的生命周期。

enum nvmf_tgt_state {

NVMF_TGT_INIT_NONE = 0, // 最初的狀態(tài)

NVMF_TGT_INIT_PARSE_CONFIG, // 解析配置文件

NVMF_TGT_INIT_CREATE_POLL_GROUPS, // 創(chuàng)建poll groups

NVMF_TGT_INIT_START_SUBSYSTEMS, // 啟動(dòng)subsystem

NVMF_TGT_INIT_START_ACCEPTOR, // 開始接收

NVMF_TGT_RUNNING, // running

NVMF_TGT_FINI_STOP_SUBSYSTEMS,

NVMF_TGT_FINI_DESTROY_POLL_GROUPS,

NVMF_TGT_FINI_STOP_ACCEPTOR,

NVMF_TGT_FINI_FREE_RESOURCES,

NVMF_TGT_STOPPED,

NVMF_TGT_ERROR,

};

首先在NVMF_TGT_INIT_PARSE_CONFIG狀態(tài)中,nvmf_tgt會(huì)去解析啟動(dòng)時(shí)傳入的配置文件,當(dāng)解析了[nvmf]這個(gè)label后,會(huì)調(diào)用spdk_nvmf_tgt_create這個(gè)方法,這個(gè)方法將初始化了全局的g_nvmf_tgt變量,同時(shí)也將tgt注冊(cè)成了一個(gè)io_device。

spdk_io_device_register(tgt,

spdk_nvmf_tgt_create_poll_group,

spdk_nvmf_tgt_destroy_poll_group,

sizeof(struct spdk_nvmf_poll_group),

“nvmf_tgt”);

spdk_nvmf_tgt_create_poll_group和spdk_nvmf_tgt_destroy_poll_group是io_channel創(chuàng)建和銷毀的回調(diào)方法。第三個(gè)參數(shù)是io_channel_ctx的size,既然這里傳入了spdk_nvmf_poll_group的大小,那么很明顯說明在nvmf中io_channel_ctx對(duì)象就是spdk_nvmf_poll_group。

當(dāng)config文件解析完了之后,nvmf_tgt狀態(tài)到了NVMF_TGT_INIT_CREATE_POLL_GROUPS,這個(gè)狀態(tài)下會(huì)為每一個(gè)線程都創(chuàng)建相應(yīng)的poll group。

spdk_for_each_thread(nvmf_tgt_create_poll_group,

NULL,

nvmf_tgt_create_poll_group_done);

static void nvmf_tgt_create_poll_group(void *ctx)

{

struct nvmf_tgt_poll_group *pg;

…。

pg-》thread = spdk_get_thread();

pg-》group = spdk_nvmf_poll_group_create(g_spdk_nvmf_tgt);

…。

}

再看spdk_nvmf_poll_group_create中,

struct spdk_nvmf_poll_group * spdk_nvmf_poll_group_create(struct spdk_nvmf_tgt *tgt)

{

struct spdk_io_channel *ch;

ch = spdk_get_io_channel(tgt);

…。

return spdk_io_channel_get_ctx(ch);

}

在spdk_get_io_channel中,會(huì)先去檢查傳入的io_device是不是已經(jīng)注冊(cè)好了的,如果已經(jīng)注冊(cè)了,將會(huì)創(chuàng)建一個(gè)新的io_channel返回,創(chuàng)建的過程會(huì)回調(diào)在注冊(cè)io_device時(shí)注冊(cè)的io_channel創(chuàng)建方法(即方法spdk_nvmf_tgt_create_poll_group)。

static int spdk_nvmf_tgt_create_poll_group(void *io_device, void *ctx_buf)

{

…。. // 初始化transport 、nvmf subsystem等

// 注冊(cè)一個(gè)poller

group-》poller = spdk_poller_register(spdk_nvmf_poll_group_poll, group, 0);

group-》thread = spdk_get_thread();

return 0;

}

在spdk_nvmf_poll_group_poll中,因?yàn)閟pdk_nvmf_poll_group對(duì)象中有transport的poll group,所以它會(huì)調(diào)用對(duì)應(yīng)的transport的poll_group_poll方法,比如rdma的poll_group_poll就會(huì)輪詢r(jià)dma注冊(cè)的poller處理每個(gè)在相應(yīng)的qpair來的請(qǐng)求,進(jìn)入rdma的狀態(tài)機(jī)將請(qǐng)求處理好。

然后這個(gè)狀態(tài)就結(jié)束了,之后再初始化好了nvmf subsystem相關(guān)的東西之后,到了狀態(tài)NVMF_TGT_INIT_START_ACCEPTOR。在這個(gè)狀態(tài)中,只注冊(cè)了一個(gè)poller。

g_acceptor_poller = spdk_poller_register(acceptor_poll, g_spdk_nvmf_tgt,

g_spdk_nvmf_tgt_conf-》acceptor_poll_rate);

這個(gè)poller調(diào)用的transport的方法,不斷的監(jiān)聽是不是有新的fd連接進(jìn)來,如果有就調(diào)用new_qpair的回調(diào)。

P3

總結(jié)

spdk thread 模型是spdk無鎖化的基礎(chǔ),在一個(gè)線程中,當(dāng)分配一個(gè)任務(wù)后,一直會(huì)運(yùn)行到任務(wù)結(jié)束為止,這確保了不需要進(jìn)行線程之間的切換而帶來額外的損耗。同時(shí),高效的spdk ring提供了不同線程之間的消息傳遞,這就使得任務(wù)結(jié)束的結(jié)果可以高效的傳遞給別的處理線程。而io_device和io_channel的設(shè)計(jì)保證了資源的抽象訪問以及獨(dú)立的路徑不去爭搶資源池,并且塊設(shè)備由于是對(duì)塊進(jìn)行操作的所以也十分適合抽象成io_device。正是因?yàn)橐陨蠋c(diǎn)才讓spdk線程模型能夠達(dá)到無鎖化且為多個(gè)target提供了基礎(chǔ)線程框架的支持。

原文標(biāo)題:SPDK線程模型解析

文章出處:【微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 處理器
    +關(guān)注

    關(guān)注

    68

    文章

    19118

    瀏覽量

    228869
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    504

    瀏覽量

    19636

原文標(biāo)題:SPDK線程模型解析

文章出處:【微信號(hào):zhuyandz,微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    開源共生 商業(yè)共贏 | RT-Thread 2024開發(fā)者大會(huì)報(bào)名啟動(dòng)!

    開發(fā)者大會(huì)將以“開源共生,商業(yè)共贏”為主題,將于2024年12月21日全天在上海臨港中心舉行。開源RT-Thread如何實(shí)現(xiàn)商業(yè)化?這一直是外界對(duì)RT-Thread
    的頭像 發(fā)表于 10-29 08:06 ?167次閱讀
    開源共生 商業(yè)共贏 | RT-<b class='flag-5'>Thread</b> 2024開發(fā)者大會(huì)報(bào)名啟動(dòng)!

    中興通訊推出星云通信大模型

    在2024MWC上海展期間,中興通訊舉辦了星云通信大模型發(fā)布會(huì),正式推出星云通信大模型系列化產(chǎn)品,涵蓋星云通信大模型、Agent工廠和系列化應(yīng)用產(chǎn)品。通過從模型到平臺(tái)再到應(yīng)用,提供煉好
    的頭像 發(fā)表于 09-14 14:18 ?512次閱讀

    6月6日杭州站RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    6月6日下午我們將在杭州舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺(tái)上實(shí)現(xiàn)同時(shí)運(yùn)行RT-Thread和linux,本次workshop邀請(qǐng)到RT-Thread
    的頭像 發(fā)表于 05-28 08:35 ?395次閱讀
    6月6日杭州站RT-<b class='flag-5'>Thread</b>線下workshop,探索RT-<b class='flag-5'>Thread</b>混合部署新模式!

    Thread網(wǎng)絡(luò)協(xié)議1.3.1版本特性介紹

    Thread Group在Thread 1.3的基礎(chǔ)上進(jìn)行了優(yōu)化,不僅修復(fù)了已知問題,還引入了一些新特性,從而推出了更新版Thread 1.3.1。
    的頭像 發(fā)表于 05-15 11:10 ?595次閱讀
    <b class='flag-5'>Thread</b>網(wǎng)絡(luò)協(xié)議1.3.1版本特性介紹

    5月16日南京站RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    5月16日下午我們將在南京舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺(tái)上實(shí)現(xiàn)同時(shí)運(yùn)行RT-Thread和linux,本次workshop邀請(qǐng)到RT-Thread
    的頭像 發(fā)表于 05-01 08:35 ?303次閱讀
    5月16日南京站RT-<b class='flag-5'>Thread</b>線下workshop,探索RT-<b class='flag-5'>Thread</b>混合部署新模式!

    RT-Thread混合部署Workshop北京站來啦!

    4月25日,下午我們將在北京舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺(tái)上實(shí)現(xiàn)同時(shí)運(yùn)行RT-Thread和linux,本次workshop邀請(qǐng)到RT-Threa
    的頭像 發(fā)表于 04-19 08:34 ?390次閱讀
    RT-<b class='flag-5'>Thread</b>混合部署Workshop北京站來啦!

    4月25日北京站RT-Thread線下workshop,探索RT-Thread混合部署新模式

    4月25日,下午我們將在北京舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺(tái)上實(shí)現(xiàn)同時(shí)運(yùn)行RT-Thread和linux,本次workshop邀請(qǐng)到RT-Threa
    的頭像 發(fā)表于 04-16 08:35 ?384次閱讀
    4月25日北京站RT-<b class='flag-5'>Thread</b>線下workshop,探索RT-<b class='flag-5'>Thread</b>混合部署新模式

    理想汽車自動(dòng)駕駛端到端模型實(shí)現(xiàn)

    理想汽車在感知、跟蹤、預(yù)測、決策和規(guī)劃等方面都進(jìn)行了模型化,最終實(shí)現(xiàn)了端到端的模型。這種模型不僅完全模型化,還能夠虛擬化,即在模擬環(huán)境中進(jìn)行
    發(fā)表于 04-12 12:17 ?395次閱讀
    理想汽車自動(dòng)駕駛端到端<b class='flag-5'>模型</b><b class='flag-5'>實(shí)現(xiàn)</b>

    4月10日深圳場RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    4月10日我們將在深圳福田舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺(tái)上實(shí)現(xiàn)同時(shí)運(yùn)行RT-Thread和linux,本次workshop邀請(qǐng)到RT-Thread
    的頭像 發(fā)表于 03-27 11:36 ?747次閱讀
    4月10日深圳場RT-<b class='flag-5'>Thread</b>線下workshop,探索RT-<b class='flag-5'>Thread</b>混合部署新模式!

    4月10日深圳場RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    4月10日我們將在深圳福田舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺(tái)上實(shí)現(xiàn)同時(shí)運(yùn)行RT-Thread和linux,本次workshop邀請(qǐng)到RT-Thread
    的頭像 發(fā)表于 03-27 08:34 ?469次閱讀
    4月10日深圳場RT-<b class='flag-5'>Thread</b>線下workshop,探索RT-<b class='flag-5'>Thread</b>混合部署新模式!

    rt-thread如何實(shí)現(xiàn)與freertos相同的功能?

    \" :: \"r\" ( ulNewMaskValue ) : \"memory\" ); } 問題 rt-thread 如何實(shí)現(xiàn)
    發(fā)表于 02-22 07:20

    Thread技術(shù)2024年發(fā)展路線分析

    Thread聯(lián)盟(Thread Group)近期發(fā)布博文說明2024年可預(yù)期的Thread標(biāo)準(zhǔn)技術(shù)更新,主要將聚焦六個(gè)增強(qiáng)功能和特性。
    的頭像 發(fā)表于 01-16 09:25 ?779次閱讀

    12/28日Thread 技術(shù)分享會(huì)-剖析全棧式Thread和Matter方案

    全方位 Thread 和 Matter 解決方案,以及完整的軟硬件技術(shù)支持進(jìn)行介紹,從而幫助開發(fā)人員實(shí)現(xiàn) Thread 技術(shù)在中國市場的應(yīng)用拓展。 掃描下方活動(dòng)議
    的頭像 發(fā)表于 12-21 18:25 ?372次閱讀
    12/28日<b class='flag-5'>Thread</b> 技術(shù)分享會(huì)-剖析全棧式<b class='flag-5'>Thread</b>和Matter方案

    RT-Thread Nano入門:獨(dú)立看門狗(IWDT)

    本文主要介紹怎么用RT-Thread Nano實(shí)現(xiàn)獨(dú)立看門狗IWDT驅(qū)動(dòng),創(chuàng)建一個(gè)喂狗線程,實(shí)現(xiàn)定時(shí)喂狗功能。
    的頭像 發(fā)表于 11-22 11:04 ?2107次閱讀
    RT-<b class='flag-5'>Thread</b> Nano入門:獨(dú)立看門狗(IWDT)

    基于RT-Thread os實(shí)現(xiàn)混合定位介紹

    wayz_iotkit 是上海圖趣信息科技有限公司,針對(duì)RT-thread開發(fā)的能夠實(shí)現(xiàn)定位功能的物聯(lián)網(wǎng)組件。
    的頭像 發(fā)表于 11-15 16:19 ?783次閱讀
    基于RT-<b class='flag-5'>Thread</b> os<b class='flag-5'>實(shí)現(xiàn)</b>混合定位介紹