1.LockSupportçparkçå¾
çåºå±å®ç°
2.Microsoft visual c++弹窗?
3.学嵌入式开发要学哪些知识
4.Linux实现ARP缓存老化时间原理问题深入解析
5.学习嵌入式,要学好嵌入式需要看那些书
6.å¦ä¹ åµå
¥å¼å¼åè¦å¦ä¹ åªäºç¥è¯
LockSupportçparkçå¾ çåºå±å®ç°
ä»ä¸ä¸ç¯æç« ä¸çJDKç延è¿éåä¸,æç»æ¯éè¿LockSupport.parkå®ç°çº¿ç¨ççå¾ ï¼é£ä¹åºå±æ¯å¦ä½å®ç°çå¾ åè¶ æ¶çå¾ çï¼æ¬ææ们æ¥æ¢è®¨ä¸ä¸ãLockSupportçparkåunparkçæ¹æ³publicstaticvoidpark(){ UNSAFE.park(false,0L);}publicstaticvoidparkNanos(longnanos){ if(nanos>0)UNSAFE.park(false,nanos);}publicstaticvoidunpark(Threadthread){ if(thread!=null)UNSAFE.unpark(thread);}ä»ä¸é¢å¯ä»¥çå°å®é LockSupport.parkæ¯éè¿Unsafeççparkæ¹æ³å®ç°ï¼ä»ä¸é¢çæ¹æ³å¯ä»¥çåºè¿ä¸ªæ¯ä¸ä¸ªnativeæ¹æ³.
/***Blockscurrentthread,returningwhenabalancing*{ @codeunpark}occurs,orabalancing{ @codeunpark}has*alreadyoccurred,orthethreadisinterrupted,or,ifnot*absoluteandtimeisnotzero,thegiventimenanosecondshave*elapsed,orifabsolute,thegivendeadlineinmilliseconds*sinceEpochhaspassed,orspuriously(i.e.,returningforno*"reason").Note:ThisoperationisintheUnsafeclassonly*because{ @codeunpark}is,soitwouldbestrangetoplaceit*elsewhere.*/publicnativevoidpark(booleanisAbsolute,longtime);JVMçUnsafeçparkæ¹æ³ä»ä¸é¢JDKä¸ä»£ç ä¸å¯ä»¥threadçParkerç对象çparkæ¹æ³è¿è¡ä¸æ®µæ¶é´ççå¾ ã
UNSAFE_ENTRY(void,Unsafe_Park(JNIEnv*env,jobjectunsafe,jbooleanisAbsolute,jlongtime)){ HOTSPOT_THREAD_PARK_BEGIN((uintptr_t)thread->parker(),(int)isAbsolute,time);EventThreadParkevent;JavaThreadParkedStatejtps(thread,time!=0);thread->parker()->park(isAbsolute!=0,time);if(event.should_commit()){ constoopobj=thread->current_park_blocker();if(time==0){ post_thread_park_event(&event,obj,min_jlong,min_jlong);}else{ if(isAbsolute!=0){ post_thread_park_event(&event,obj,min_jlong,time);}else{ post_thread_park_event(&event,obj,time,min_jlong);}}}HOTSPOT_THREAD_PARK_END((uintptr_t)thread->parker());}UNSAFE_ENDThread.hppçæ件ä¸å é¨å®ä¹çPark对象
private:Parker_parker;public:Parker*parker(){ return&_parker;}ä¸é¢æ¯Os_posix.cppä¸æ¯Linuxä¸å®ç°çParkçparkçå®ç°æ¹å¼
é¦å å°_counterçåééè¿CAS设置为0ï¼è¿åå°±æ§çå¼ï¼å¦æä¹åæ¯å¤§äº0ï¼å说ææ¯å 许访é®ï¼ä¸ç¨é»å¡ï¼ç´æ¥è¿åã
è·åå½å线ç¨ã
å¤æ线ç¨æ¯å¦æ¯ä¸æä¸ï¼å¦ææ¯ï¼åç´æ¥è¿åï¼(ä¹å°±æ¯è¯´çº¿ç¨å¤äºä¸æç¶æä¸ä¼å¿½ç¥parkï¼ä¸ä¼é»å¡çå¾ )
å¤æå¦æä¼ å ¥çtimeåæ°å°äº0 æè æ¯ç»å¯¹æ¶é´å¹¶ä¸timeæ¯0,åç´æ¥è¿å,(ä¸é¢çUnsafeè°ç¨parkä¼ å ¥çåæ°æ¯ falseã0ï¼æ以ä¸æ»¡è¶³è¿ç§æ åµ)
å¦ætime大äº0ï¼å转æ¢æç»å¯¹æ¶é´ã
å建ThreadBlockInVM对象ï¼å¹¶ä¸è°ç¨pthread_mutex_trylockè·å线ç¨äºæ¥éï¼å¦æ没æè·åå°éï¼åç´æ¥è¿åï¼
å¤æ_counteråéæ¯å¦å¤§äº0ï¼å¦ææ¯ï¼åéç½®_counter为0ï¼éæ¾çº¿ç¨éï¼ç´æ¥è¿åã
è°ç¨ OrderAccess::fence(); å å ¥å åå±éï¼ç¦æ¢æ令éæåºï¼ç¡®ä¿å éåéæ¾éçæ令ç顺åºã
å建OSThreadWaitState对象ï¼
å¤ætimeæ¯å¦å¤§äº0ï¼å¦ææ¯0ï¼åè°ç¨pthread_cond_waitè¿è¡çå¾ ï¼å¦æä¸æ¯0ï¼ç¶åè°ç¨pthread_cond_timedwaitè¿è¡æ¶é´åæ°ä¸ºabsTimeççå¾ ï¼
è°ç¨pthread_mutex_unlockè¿è¡éæ¾_mutexéï¼
å次è°ç¨OrderAccess::fence()ç¦æ¢æ令éæåºã
//Parker::parkdecrementscountif>0,elsedoesacondvarwait.Unpark//setscountto1andsignalscondvar.Onlyonethreadeverwaits//onthecondvar.Contentionseenwhentryingtoparkimpliesthatsomeone//isunparkingyou,sodon'twait.Andspuriousreturnsarefine,sothere//isnoneedtotracknotifications.voidParker::park(boolisAbsolute,jlongtime){ //Optionalfast-pathcheck://Returnimmediatelyifapermitisavailable.//WedependonAtomic::xchg()havingfullbarriersemantics//sincewearedoingalock-freeupdateto_counter.if(Atomic::xchg(&_counter,0)>0)return;JavaThread*jt=JavaThread::current();//Optionaloptimization--avoidstatetransitionsifthere's//aninterruptpending.if(jt->is_interrupted(false)){ return;}//Next,demultiplex/decodetimeargumentsstructtimespecabsTime;if(time<0||(isAbsolute&&time==0)){ //don'twaitatallreturn;}if(time>0){ to_abstime(&absTime,time,isAbsolute,false);}//Entersafepointregion//Bewareofdeadlockssuchas.//Theper-threadParker::mutexisaclassicleaf-lock.//InparticularathreadmustneverblockontheThreads_lockwhile//holdingtheParker::mutex.Ifsafepointsarependingboththe//theThreadBlockInVM()CTORandDTORmaygrabThreads_lock.ThreadBlockInVMtbivm(jt);//Can'taccessinterruptstatenowthatweare_thread_blocked.Ifwe've//beeninterruptedsincewecheckedabovethen_counterwillbe>0.//Don'twaitifcannotgetlocksinceinterferencearisesfrom//unparking.if(pthread_mutex_trylock(_mutex)!=0){ return;}intstatus;if(_counter>0){ //nowaitneeded_counter=0;status=pthread_mutex_unlock(_mutex);assert_status(status==0,status,"invariant");//Paranoiatoensureourlockedandlock-freepathsinteract//correctlywitheachotherandJava-levelaccesses.OrderAccess::fence();return;}OSThreadWaitStateosts(jt->osthread(),false/*notObject.wait()*/);assert(_cur_index==-1,"invariant");if(time==0){ _cur_index=REL_INDEX;//arbitrarychoicewhennottimedstatus=pthread_cond_wait(&_cond[_cur_index],_mutex);assert_status(status==0MACOS_ONLY(||status==ETIMEDOUT),status,"cond_wait");}else{ _cur_index=isAbsolute?ABS_INDEX:REL_INDEX;status=pthread_cond_timedwait(&_cond[_cur_index],_mutex,&absTime);assert_status(status==0||status==ETIMEDOUT,status,"cond_timedwait");}_cur_index=-1;_counter=0;status=pthread_mutex_unlock(_mutex);assert_status(status==0,status,"invariant");//Paranoiatoensureourlockedandlock-freepathsinteract//correctlywitheachotherandJava-levelaccesses.OrderAccess::fence();Linuxæä½ç³»ç»æ¯å¦ä½å®ç°pthread_cond_timedwaitè¿è¡æ¶é´çå¾ çpthread_cond_timedwaitå½æ°ä½äºglibcä¸pthread_cond_wait.c, å¯ä»¥çå°æ¯è°ç¨__pthread_cond_wait_commonå®ç°
/*See__pthread_cond_wait_common.*/int___pthread_cond_timedwait(pthread_cond_t*cond,pthread_mutex_t*mutex,conststruct__timespec*abstime){ /*Checkparametervalidity.ThisshouldalsotellthecompilerthatitcanassumethatabstimeisnotNULL.*/if(!valid_nanoseconds(abstime->tv_nsec))returnEINVAL;/*RelaxedMOissufficebecauseclockIDbitisonlymodifiedinconditioncreation.*/unsignedintflags=atomic_load_relaxed(&cond->__data.__wrefs);clockid_tclockid=(flags&__PTHREAD_COND_CLOCK_MONOTONIC_MASK)?CLOCK_MONOTONIC:CLOCK_REALTIME;return__pthread_cond_wait_common(cond,mutex,clockid,abstime);}ä¸é¢__pthread_cond_wait_commonæ¯å®ç°éè¿__futex_abstimed_wait_cancelableå®ç°æ¶é´çå¾
static__always_inlineint__pthread_cond_wait_common(pthread_cond_t*cond,pthread_mutex_t*mutex,clockid_tclockid,conststruct__timespec*abstime){ ''çç¥''`err=__futex_abstimed_wait_cancelable(cond->__data.__g_signals+g,0,clockid,abstime,private);''çç¥''`}__futex_abstimed_wait_cancelableæ¯è°ç¨__futex_abstimed_wait_common
int__futex_abstimed_wait_cancelable(unsignedint*futex_word,unsignedintexpected,clockid_tclockid,conststruct__timespec*abstime,intprivate){ return__futex_abstimed_wait_common(futex_word,expected,clockid,abstime,private,true);}__futex_abstimed_wait_commonä¸é¢åæ¯éè¿å¤æå¹³å°æ¯ä½æè ä½,è°ç¨__futex_abstimed_wait_commonæè __futex_abstimed_wait_common
staticint__futex_abstimed_wait_common(unsignedint*futex_word,unsignedintexpected,clockid_tclockid,conststruct__timespec*abstime,intprivate,boolcancel){ interr;unsignedintclockbit;/*Workaroundthefactthatthekernelrejectsnegativetimeoutvaluesdespitethembeingvalid.*/if(__glibc_unlikely((abstime!=NULL)&&(abstime->tv_sec<0)))returnETIMEDOUT;if(!lll_futex_supported_clockid(clockid))returnEINVAL;clockbit=(clockid==CLOCK_REALTIME)?FUTEX_CLOCK_REALTIME:0;intop=__lll_private_flag(FUTEX_WAIT_BITSET|clockbit,private);#ifdef__ASSUME_TIME_SYSCALLSerr=__futex_abstimed_wait_common(futex_word,expected,op,abstime,private,cancel);#elseboolneed_time=abstime!=NULL&&!in_time_t_range(abstime->tv_sec);if(need_time){ err=__futex_abstimed_wait_common(futex_word,expected,op,abstime,private,cancel);if(err==-ENOSYS)err=-EOVERFLOW;}elseerr=__futex_abstimed_wait_common(futex_word,expected,op,abstime,private,cancel);#endifswitch(err){ case0:case-EAGAIN:case-EINTR:case-ETIMEDOUT:case-EINVAL:case-EOVERFLOW:/*Passedabsolutetimeoutusesbittime_ttype,butunderlyingkerneldoesnotsupportbittime_tfutexsyscalls.*/return-err;case-EFAULT:/*Musthavebeencausedbyaglibcorapplicationbug.*/case-ENOSYS:/*Musthavebeencausedbyaglibcbug.*//*Noothererrorsaredocumentedatthistime.*/default:futex_fatal_error();}}__futex_abstimed_wait_commonæ¯è°ç¨INTERNAL_SYSCALL_CANCELå®å®ä¹å®ç°
staticint__futex_abstimed_wait_common(unsignedint*futex_word,unsignedintexpected,intop,conststruct__timespec*abstime,intprivate,boolcancel){ if(cancel)returnINTERNAL_SYSCALL_CANCEL(futex_time,futex_word,op,expected,abstime,NULL/*Unused.*/,FUTEX_BITSET_MATCH_ANY);elsereturnINTERNAL_SYSCALL_CALL(futex_time,futex_word,op,expected,abstime,NULL/*Ununsed.*/,FUTEX_BITSET_MATCH_ANY);}ç³»ç»è°ç¨ççå®å®ä¹
/***Blockscurrentthread,returningwhenabalancing*{ @codeunpark}occurs,orabalancing{ @codeunpark}has*alreadyoccurred,orthethreadisinterrupted,or,ifnot*absoluteandtimeisnotzero,thegiventimenanosecondshave*elapsed,orifabsolute,thegivendeadlineinmilliseconds*sinceEpochhaspassed,orspuriously(i.e.,returningforno*"reason").Note:ThisoperationisintheUnsafeclassonly*because{ @codeunpark}is,soitwouldbestrangetoplaceit*elsewhere.*/publicnativevoidpark(booleanisAbsolute,longtime);0æ»ç»ä¸»è¦å¯¹LockSupportçparkçå¾ å®ç°çåºå±å®ç°çæµ æï¼é对äºLinuxçç³»ç»è°ç¨è¿æ²¡ææ¾å°æºç ï¼åç»ä¼ç»§ç»è·è¸ªï¼å¸ææ读è ç¥éç满å¸å¯ä»¥åç¥ä¸ï¼è°¢è°¢ã
é¾æ¥ï¼/post/Microsoft visual c++弹窗?
适用于 Linux 的 Windows 子系统中的 Visual Studio Code 服务器使用本地 WebSocket WebSocket 连接与远程 WSL 扩展进行通信。网站中的 JavaScript 可以连接到该服务器并在目标系统上执行任意命令。目前该漏洞被命名为CVE--。
这些漏洞可以被用于:
本地 WebSocket 服务器正在监控所有接口。如果允许通过 Windows 防火墙,知识付费系统源码外部应用程序可能会连接到此服务器。
本地 WebSocket 服务器不检查 WebSocket 握手中的 Origin 标头或具有任何身份验证模式。浏览器中的 JavaScript 可以连接到该服务器。即使服务器正在监控本地主机,也是如此。
我们可以在特定端口上生成一个Node Inspector示例,它还监控所有接口。外部应用程序可以连接到它。
如果外部应用程序或本地网站可以连接到这些服务器中的任何一个,它们就可以在目标计算机上运行任意代码。
Visual Studio Code 库是不断更新的。我将使用一个特定的提交 (bbcaf3db8bb8adf0ccfa)。
$ git clone t) == 1 //n-used可能会因为“本地确认”机制而向前推进
(state == NUD_FAILED ||time_after(now, n-used + n-parms-gc_staletime))) {
*np = n-next;
n-dead = 1;
write_unlock(n-lock);
neigh_release(n);
continue;
}
if (atomic_read(n-refcnt) == 1 //n-used可能会因为“本地确认”机制而向前推进
(state == NUD_FAILED ||time_after(now, n-used + n-parms-gc_staletime))) {
*np = n-next;
n-dead = 1;
write_unlock(n-lock);
neigh_release(n);
continue;
}
如果在实验中,你的处于stale状态的表项没有被及时删除,那么试着执行一下下面的命令:
[plain] view plaincopyprint?ip route flush cache
ip route flush cache然后再看看ip neigh ls all的结果,注意,不要指望马上会被删除,因为此时垃圾回收定时器还没有到期呢...但是我敢保证,不长的时间之后,该缓存表项将被删除。
五.第一个问题的解决
在启用keepalived进行基于vrrp热备份的群组上,很多同学认为根本不需要在进入master状态时重新绑定自己的MAC地址和虚拟IP地址,然而这是新网源码根本错误的,如果说没有出现什么问题,那也是侥幸,因为各个路由器上默认配置的arp超时时间一般很短,然而我们不能依赖这种配置。请看下面的图示:
如果发生了切换,假设路由器上的arp缓存超时时间为1小时,那么在将近一小时内,单向数据将无法通信(假设群组中的主机不会发送数据通过路由器,排出“本地确认”,毕竟我不知道路由器是不是在运行Linux),路由器上的数据将持续不断的法往原来的master,然而原始的matser已经不再持有虚拟IP地址。
因此,为了使得数据行为不再依赖路由器的配置,必须在vrrp协议下切换到master时手动绑定虚拟IP地址和自己的MAC地址,在Linux上使用方便的arping则是:
[plain] view plaincopyprint?arping -i ethX -S 1.1.1.1 -B -c 1
arping -i ethX -S 1.1.1.1 -B -c 1这样一来,获得1.1.1.1这个IP地址的master主机将IP地址为...的ARP请求广播到全网,假设路由器运行Linux,则路由器接收到该ARP请求后将根据来源IP地址更新其本地的ARP缓存表项(如果有的话),然而问题是,该表项更新的结果状态却是stale,这只是ARP的规定,具体在代码中体现是这样的,在arp_process函数的最后:
复制代码
代码如下:
if (arp-ar_op != htons(ARPOP_REPLY) || skb-pkt_type != PACKET_HOST)
state = NUD_STALE;
neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0);
if (arp-ar_op != htons(ARPOP_REPLY) || skb-pkt_type != PACKET_HOST)
state = NUD_STALE;
neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0);
由此可见,只有实际的外发包的下一跳是1.1.1.1时,才会通过“本地确认”机制或者实际发送ARP请求的方式将对应的MAC地址映射reachable状态。
更正:在看了keepalived的源码之后,发现这个担心是篮球源码多余的,毕竟keepalived已经很成熟了,不应该犯“如此低级的错误”,keepalived在某主机切换到master之后,会主动发送免费arp,在keepalived中有代码如是:
复制代码
代码如下:
vrrp_send_update(vrrp_rt * vrrp, ip_address * ipaddress, int idx)
{
char *msg;
char addr_str[];
if (!IP_IS6(ipaddress)) {
msg = "gratuitous ARPs";
inet_ntop(AF_INET, ipaddress-u.sin.sin_addr, addr_str, );
send_gratuitous_arp(ipaddress);
} else {
msg = "Unsolicited Neighbour Adverts";
inet_ntop(AF_INET6, ipaddress-u.sin6_addr, addr_str, );
ndisc_send_unsolicited_na(ipaddress);
}
if (0 == idx debug ) {
log_message(LOG_INFO, "VRRP_Instance(%s) Sending %s on %s for %s",
vrrp-iname, msg, IF_NAME(ipaddress-ifp), addr_str);
}
}
vrrp_send_update(vrrp_rt * vrrp, ip_address * ipaddress, int idx)
{
char *msg;
char addr_str[];
if (!IP_IS6(ipaddress)) {
msg = "gratuitous ARPs";
inet_ntop(AF_INET, ipaddress-u.sin.sin_addr, addr_str, );
send_gratuitous_arp(ipaddress);
} else {
msg = "Unsolicited Neighbour Adverts";
inet_ntop(AF_INET6, ipaddress-u.sin6_addr, addr_str, );
ndisc_send_unsolicited_na(ipaddress);
}
if (0 == idx debug ) {
log_message(LOG_INFO, "VRRP_Instance(%s) Sending %s on %s for %s",
vrrp-iname, msg, IF_NAME(ipaddress-ifp), addr_str);
}
}
六.第二个问题的解决
扯了这么多,在Linux上到底怎么设置ARP缓存的老化时间呢?
我们看到/proc/sys/net/ipv4/neigh/ethX目录下面有多个文件,到底哪个是ARP缓存的老化时间呢?实际上,直接点说,就是base_reachable_time这个文件。其它的都只是优化行为的措施。比如gc_stale_time这个文件记录的是“ARP缓存表项的缓存”的存活时间,该时间只是一个缓存的缓存的存活时间,在该时间内,如果需要用到该邻居,那么直接使用表项记录的数据作为ARP请求的内容即可,或者得到“本地确认”后直接将其置为reachable状态,而不用再通过路由查找,ARP查找,ARP邻居创建,ARP邻居解析这种慢速的方式。
默认情况下,reachable状态的超时时间是秒,超过秒,ARP缓存表项将改为stale状态,此时,你可以认为该表项已经老化到期了,只是Linux的实现中并没有将其删除罢了,再过了gc_stale_time时间,体检 源码表项才被删除。在ARP缓存表项成为非reachable之后,垃圾回收器负责执行“再过了gc_stale_time时间,表项才被删除”这件事,这个定时器的下次到期时间是根据base_reachable_time计算出来的,具体就是在neigh_periodic_timer中:
复制代码
代码如下:
if (time_after(now, tbl-last_rand + * HZ)) {
struct neigh_parms *p;
tbl-last_rand = now;
for (p = tbl-parms; p; p = p-next)
//随计化很重要,防止“共振行为”引发的ARP解析风暴
p-reachable_time =neigh_rand_reach_time(p-base_reachable_time);
}
...
expire = tbl-parms.base_reachable_time 1;
expire /= (tbl-hash_mask + 1);
if (!expire)
expire = 1;
mod_timer(tbl-gc_timer, now + expire);
if (time_after(now, tbl-last_rand + * HZ)) {
struct neigh_parms *p;
tbl-last_rand = now;
for (p = tbl-parms; p; p = p-next)
//随计化很重要,防止“共振行为”引发的ARP解析风暴
p-reachable_time =neigh_rand_reach_time(p-base_reachable_time);
}
...
expire = tbl-parms.base_reachable_time 1;
expire /= (tbl-hash_mask + 1);
if (!expire)
expire = 1;
mod_timer(tbl-gc_timer, now + expire);
可见一斑啊!适当地,我们可以通过看代码注释来理解这一点,好心人都会写上注释的。为了实验的条理清晰,我们设计以下两个场景:
1.使用iptables禁止一切本地接收,从而屏蔽arp本地确认,使用sysctl将base_reachable_time设置为5秒,将gc_stale_time为5秒。
2.关闭iptables的禁止策略,使用TCP下载外部网络一个超大文件或者进行持续短连接,使用sysctl将base_reachable_time设置为5秒,将gc_stale_time为5秒。
在两个场景下都使用ping命令来ping本地局域网的默认网关,然后迅速Ctrl-C掉这个ping,用ip neigh show all可以看到默认网关的arp表项,然而在场景1下,大约5秒之内,arp表项将变为stale之后不再改变,再ping的话,表项先变为delay再变为probe,太极源码然后为reachable,5秒之内再次成为stale,而在场景2下,arp表项持续为reachable以及dealy,这说明了Linux中的ARP状态机。那么为何场景1中,当表项成为stale之后很久都不会被删除呢?其实这是因为还有路由缓存项在使用它,此时你删除路由缓存之后,arp表项很快被删除。
七.总结
1.在Linux上如果你想设置你的ARP缓存老化时间,那么执行sysctl -w net.ipv4.neigh.ethX=Y即可,如果设置别的,只是影响了性能,在Linux中,ARP缓存老化以其变为stale状态为准,而不是以其表项被删除为准,stale状态只是对缓存又进行了缓存;
2.永远记住,在将一个IP地址更换到另一台本网段设备时,尽可能快地广播免费ARP,在Linux上可以使用arping来玩小技巧。
学习嵌入式,要学好嵌入式需要看那些书
如果需要嵌入式的话,我个人推荐一些嵌入式需要看的书给你做参考
Linux基础
1、《Linux与UnixShell编程指南》
C语言基础
1、《CPrimerPlus,5thEdition》美StephenPrata着
2、《TheCProgrammingLanguage,2ndEdition》美BrianW.KernighanDav
idM.Rithie(K&R)着
3、《AdvancedProgrammingintheUNIXEnvironment,2ndEdition》(APUE)
4、《嵌入式Linux应用程序开发详解》
Linux内核
1、《深入理解Linux内核》(第三版)
2、《Linux内核源代码情景分析》毛德操胡希明著
研发方向
1、《UNIXNetworkProgramming》(UNP)
2、《TCP/IP详解》
3、《Linux内核编程》
4、《Linux设备驱动开发》(LDD)
5、《Linux高级程序设计》杨宗德著
硬件基础
1、《ARM体系结构与编程》杜春雷着
2、S3CDatasheet
英语基础
1、《计算机与通信专业英语》
系统教程
1、《嵌入式系统――体系结构、编程与设计》
2、《嵌入式系统――采用公开源代码和StrongARM/Xscale处理器》毛德操胡希明
著
3、《BuildingEmbeddedLinuxSystems》
4、《嵌入式ARM系统原理与实例开发》杨宗德著
理论基础
1、《算法导论》
2、《数据结构(C语言版)》
3、《计算机组织与体系结构?性能分析》
4、《深入理解计算机系统》美RandalE.Bryant DavidO''Hallaron着
5、《操作系统:精髓与设计原理》
6、《编译原理》
7、《数据通信与计算机网络》
8、《数据压缩原理与应用》
C语言书籍推荐
1.TheCprogramminglanguage《C程序设计语言》
2.PointersonC《C和指针》
3.Ctrapsandpitfalls《C陷阱与缺陷》
4.ExpertCLanuage《专家C编程》
5.WritingCleanCode-----MicrosoftTechiniquesforDevelopingBug-freeCProgr
ams
《编程精粹--Microsoft编写优质无错C程序秘诀》
6.ProgrammingEmbeddedSystemsinCandC++《嵌入式系统编程》
7.《C语言嵌入式系统编程**》
8.《高质量C++/C编程指南》林锐
看书的话比较晦涩难懂,我个人推荐看视频教程,有老师带着比较容易理解,我推荐IT学习联盟的零基础嵌入式就业班,这是一套完整的嵌入式视频教程,他从零基础教起,特别适合初学者,感兴趣,可以去看看。
å¦ä¹ åµå ¥å¼å¼åè¦å¦ä¹ åªäºç¥è¯
é¦å éè¦Cè¯è¨åºç¡ï¼æ°æ®ç»æï¼linuxå½ä»¤ï¼ç½ç»ç¼ç¨ï¼æä½ç³»ç»ï¼æ°æ®åºï¼ç§»æ¤å æ ¸ï¼é©±å¨ç¼ç¨ï¼åç§æ»çº¿ç¥è¯ï¼éä¿¡åè®®ï¼ç¡¬ä»¶å软件ç¥è¯ï¼ä¸å±ååºå±ç软件ç¥è¯é½éè¦ææäºè§£ï¼å°±ç®ä½ ä¸åå ·ä½çç¼ç¨ï¼ä¹è¦ç¥éä¸ç¹å·¥ä½åçï¼å 为åµå ¥å¼å¼åéè¦èèçæ¯æ´ä¸ªç¨åº
AMD的ROCM平台是什么?
揭开AMD ROCm神秘面纱:高性能GPU计算平台的全面解析AMD ROCm,这个名字背后隐藏着一个强大的开源GPU计算生态系统。它不仅仅是一个堆栈,而是一系列精心设计的组件,旨在为高性能计算(HPC)、人工智能(AI)和科学计算等领域提供卓越性能和跨平台的灵活性。由Open Source Software(OSS)驱动,ROCm包含驱动程序、开发工具和API,如OpenMP和OpenCL,以及集成的机器学习框架,如PyTorch和TensorFlow。核心组件包括驱动、编译器、运行时库和工具集,支持AMD GPU、APU和多架构处理器,目标是打造一个高性能且可移植的GPU计算平台,与NVIDIA的CUDA相媲美。
ROCm项目的基石是AMD Radeon Open Computing,类似于CUDA,通过ROCm系列项目和HSA(异构系统架构)实现。AMD与众多伙伴合作,利用GCN(AMD GPU架构)等技术,构建了一个兼容且高效的runtime和架构API。与CUDA相比,ROCm利用HIP在多个平台上部署便携式应用,如A卡用HIP或OpenCL,而N卡则使用CUDA。此外,ROCm的软件栈中内置了rocFFT、rocBLAS、rocRAND和rocSPARSE等加速库,进一步提升计算效率。
要使用ROCm,开发者可以借助标准Linux编译器(如GCC、ICC、CLANG),以C或C++编程,主要依赖hip_runtime.h,它包含了hip_runtime_api.h和hipLaunchKernelGGL的核心内容。尽管hip_runtime.h支持C++,但公开函数相对有限。特别地,AMD和NVIDIA的实现细节分别存储在amd_detail/**和nvidia_detail/**中,直接使用需谨慎。hipcc作为编译器驱动,取代CUDA的nvcc,而hipconfig则帮助查看配置信息。使用ROCm源码时,需设置特定的分支(如ROCM-5.6.x),并安装对应的驱动和预构建包,以下是关键步骤:
1. 设置仓库分支(如ROCM-5.6.x)和环境变量ROCM_PATH(默认在/opt/rocm)。
2. 克隆必要的GitHub仓库,如HIP、HIPCC和clr。
3. 配置环境变量指向仓库目录,包括HIP、HSA、HIP_CLANG_PATH等。
4. 构建HIPCC运行时,依赖HIP和ROCclr,可能需要指定特定平台选项。
5. 对于HIPCLR,指定相关目录和安装选项,hip运行时默认安装在$PWD/install。
从ROCM 5.6开始,clr库合并了ROCclr、HIPAMD和OpenCL,提供更为集成的体验。同时,AMDDeviceLibs和ROCm-CompilerSupport库的管理与构建细节需要遵循特定指南,CMake的使用和依赖设置也尤为重要。
AMD的HSA架构使得开发者能直接利用GPU性能,HSA运行时API提供了错误处理、内存管理和高级调度等接口。AQL作为数据包标准,支持细粒度和粗粒度内存访问,程序员需深入理解HSA运行时手册以充分利用其功能。
要编译HSA运行时,你需要ROCT-Thunk-Interface库,并可能需要加入特定用户组。ROCt库依赖于ROCk驱动,其入门指南提供了系统兼容性、内核和硬件支持信息。构建和安装ROCm包的过程包括使用cmake构建,然后进行安装和软件包打包。
最后,ROCm生态系统的数学库如rocFFT、rocBLAS等,为高性能计算提供了强大的工具。这些库的详细信息和GitHub链接,为开发者提供了丰富的资源库,让性能优化触手可及。
总之,AMD ROCm是一个强大的工具,为开发者提供了一站式GPU计算解决方案,无论是科研、AI还是游戏开发,都能从中受益。通过深入了解和利用这一平台,你可以解锁GPU计算的无限可能。