免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: folklore
打印 上一主题 下一主题

[其他] 应PM要求,装B一次以满足其虚荣心。 [复制链接]

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
51 [报告]
发表于 2012-10-28 11:37 |只看该作者
回复 50# gvim


    对于实时性任务,CPU时间的重要性无法和任务的实时性相提并论的。

比如说好奇号,我宁愿在摄像头后面再多装一个CPU,我也绝对不把主芯片做成分时然后同时跑机器视觉和主程序——多装CPU撑死了也就多个几千美元,万一没看到前面的悬崖那几亿美元就报销了。那么,对于那个专门处理计算机视觉的CPU,就无所谓CPU时间资源了——整个CPU就为了搞一件事而已。

实时不仅仅是deadline,如果是机器人,那么对于每个时间做什么事情都要有严格限制,对于一些关键任务,比如说改变电机方向这种,提前了或者推迟了都不行,要严格控制,所以在执行这样的重要任务的时候,直接关掉调度器是最合适的。

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
52 [报告]
发表于 2012-10-28 11:50 |只看该作者
starwing83 发表于 2012-10-28 11:37
回复 50# gvim


那是你的设计问题,不是RTOS的问题。RTOS没有说是任务管理的银弹,很多场景确实就是轮询最合适。单片机便宜的才几块钱,专门做这个任务没什么问题。

》》》我还是忍不住想说一下,除了伪实时操作系统,真正的实时操作系统都是不会有线程的概念的。
线程和任务在这个领域里没区别,只是名词不一样。就像cjzzzz前两天举例说的电子领域里叫固件开发,做软件的就叫嵌入式吧。这里的任务还是有调度,只不过调度策略相对简单。
我的意思是,RTOS不是说有任务/线程就不是RTOS,而是说你的实时性要求可否用你采用的RTOS来满足,或者中断响应能否满足你需要的实时性,这才是做之前应该论证的东西。

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
53 [报告]
发表于 2012-10-28 11:54 |只看该作者
RTEMS,vxworks里面照样有线程/任务的东西。
有否上下文切换这不是区分实时与否的参数

论坛徽章:
0
54 [报告]
发表于 2012-10-28 12:00 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
55 [报告]
发表于 2012-10-28 12:22 |只看该作者
回复 52# gvim


    你可能是将“需要实时处理的任务”(根据实时的约束不同,可以选用不同的操作系统)和“为实时任务设计的操作系统”(操作系统的目的,就是为了为实时任务提供最好的支持)给搞混了。

前者说明一个任务有实时要求,因此只要满足这个要求的操作系统——哪怕是通用的——都OK。

后者说明这个操作系统就是为了实时而设计的,只要硬件时间辨析度支持,那么可以支持任意实时要求的任务。

这里说的是,如果你的任务对实时要求并不是很高——比如仅仅是一个会根据人的走动而走动的机器人——那么用普通的通用操作系统也是可以的。

然而,如果你的要求本身就需要高实时性,那么配置高性能CPU+通用操作系统,是不如直接配置合适的CPU+实时操作系统的。工业用的流水线焊接机器人就是这种。

所以我才会说,这样的情形下,用线程和锁去进行这样的任务,是很不合适的。

论坛徽章:
4
天秤座
日期:2013-10-18 13:58:33金牛座
日期:2013-11-28 16:17:01辰龙
日期:2014-01-14 09:54:32戌狗
日期:2014-01-24 09:23:27
56 [报告]
发表于 2012-12-03 23:24 |只看该作者
鬼使神差翻到此贴,楼主得顶啊~~~~

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
57 [报告]
发表于 2012-12-04 14:54 |只看该作者
  1. Brennan's Guide to Inline Assembly
  2. by Brennan "Bas" Underwood
  3. Document version 1.1.2.2
  4. Ok. This is meant to be an introduction to inline assembly under DJGPP. DJGPP is based on GCC, so it uses the AT&T/UNIX syntax and has a somewhat unique method of inline assembly. I spent many hours figuring some of this stuff out and told Info that I hate it, many times.

  5. Hopefully if you already know Intel syntax, the examples will be helpful to you. I've put variable names, register names and other literals in bold type.


  6. The Syntax
  7. So, DJGPP uses the AT&T assembly syntax. What does that mean to you?
  8. Register naming:
  9. Register names are prefixed with "%". To reference eax:
  10. AT&T:  %eax
  11. Intel: eax

  12. Source/Destination Ordering:
  13. In AT&T syntax (which is the UNIX standard, BTW) the source is always on the left, and the destination is always on the right.
  14. So let's load ebx with the value in eax:
  15. AT&T:  movl %eax, %ebx
  16. Intel: mov ebx, eax

  17. Constant value/immediate value format:
  18. You must prefix all constant/immediate values with "$".
  19. Let's load eax with the address of the "C" variable booga, which is static.
  20. AT&T:  movl $_booga, %eax
  21. Intel: mov eax, _booga

  22. Now let's load ebx with 0xd00d:
  23. AT&T:  movl $0xd00d, %ebx
  24. Intel: mov ebx, d00dh

  25. Operator size specification:
  26. You must suffix the instruction with one of b, w, or l to specify the width of the destination register as a byte, word or longword. If you omit this, GAS (GNU assembler) will attempt to guess. You don't want GAS to guess, and guess wrong! Don't forget it.
  27. AT&T:  movw %ax, %bx
  28. Intel: mov bx, ax

  29. The equivalent forms for Intel is byte ptr, word ptr, and dword ptr, but that is for when you are...
  30. Referencing memory:
  31. DJGPP uses 386-protected mode, so you can forget all that real-mode addressing junk, including the restrictions on which register has what default segment, which registers can be base or index pointers. Now, we just get 6 general purpose registers. (7 if you use ebp, but be sure to restore it yourself or compile with -fomit-frame-pointer.)
  32. Here is the canonical format for 32-bit addressing:
  33. AT&T:  immed32(basepointer,indexpointer,indexscale)
  34. Intel: [basepointer + indexpointer*indexscale + immed32]

  35. You could think of the formula to calculate the address as:
  36.   immed32 + basepointer + indexpointer * indexscale

  37. You don't have to use all those fields, but you do have to have at least 1 of immed32, basepointer and you MUST add the size suffix to the operator!
  38. Let's see some simple forms of memory addressing:

  39. Addressing a particular C variable:

  40. AT&T:  _booga
  41. Intel: [_booga]

  42. Note: the underscore ("_") is how you get at static (global) C variables from assembler. This only works with global variables. Otherwise, you can use extended asm to have variables preloaded into registers for you. I address that farther down.

  43. Addressing what a register points to:

  44. AT&T:  (%eax)
  45. Intel: [eax]



  46. Addressing a variable offset by a value in a register:

  47. AT&T: _variable(%eax)
  48. Intel: [eax + _variable]



  49. Addressing a value in an array of integers (scaling up by 4):

  50. AT&T:  _array(,%eax,4)
  51. Intel: [eax*4 + array]



  52. You can also do offsets with the immediate value:

  53. C code: *(p+1) where p is a char *
  54. AT&T:  1(%eax) where eax has the value of p
  55. Intel: [eax + 1]



  56. You can do some simple math on the immediate value:

  57. AT&T: _struct_pointer+8

  58. I assume you can do that with Intel format as well.

  59. Addressing a particular char in an array of 8-character records:
  60. eax holds the number of the record desired. ebx has the wanted char's offset within the record.

  61. AT&T:  _array(%ebx,%eax,8)
  62. Intel: [ebx + eax*8 + _array]

  63. Whew. Hopefully that covers all the addressing you'll need to do. As a note, you can put esp into the address, but only as the base register.
  64. Basic inline assembly
  65. The format for basic inline assembly is very simple, and much like Borland's method.
  66. asm ("statements");

  67. Pretty simple, no? So
  68. asm ("nop");

  69. will do nothing of course, and
  70. asm ("cli");

  71. will stop interrupts, with
  72. asm ("sti");

  73. of course enabling them. You can use __asm__ instead of asm if the keyword asm conflicts with something in your program.
  74. When it comes to simple stuff like this, basic inline assembly is fine. You can even push your registers onto the stack, use them, and put them back.

  75. asm ("pushl %eax\n\t"
  76.      "movl $0, %eax\n\t"
  77.      "popl %eax");

  78. (The \n's and \t's are there so the .s file that GCC generates and hands to GAS comes out right when you've got multiple statements per asm.)
  79. It's really meant for issuing instructions for which there is no equivalent in C and don't touch the registers.
  80. But if you do touch the registers, and don't fix things at the end of your asm statement, like so:

  81. asm ("movl %eax, %ebx");
  82. asm ("xorl %ebx, %edx");
  83. asm ("movl $0, _booga");

  84. then your program will probably blow things to hell. This is because GCC hasn't been told that your asm statement clobbered ebx and edx and booga, which it might have been keeping in a register, and might plan on using later. For that, you need:
  85. Extended inline assembly
  86. The basic format of the inline assembly stays much the same, but now gets Watcom-like extensions to allow input arguments and output arguments.
  87. Here is the basic format:

  88. asm ( "statements" : output_registers : input_registers : clobbered_registers);

  89. Let's just jump straight to a nifty example, which I'll then explain:

  90. asm ("cld\n\t"
  91.      "rep\n\t"
  92.      "stosl"
  93.      : /* no output registers */
  94.      : "c" (count), "a" (fill_value), "D" (dest)
  95.      : "%ecx", "%edi" );

  96. The above stores the value in fill_value count times to the pointer dest.
  97. Let's look at this bit by bit.

  98. asm ("cld\n\t"

  99. We are clearing the direction bit of the flags register. You never know what this is going to be left at, and it costs you all of 1 or 2 cycles.
  100.      "rep\n\t"
  101.      "stosl"

  102. Notice that GAS requires the rep prefix to occupy a line of it's own. Notice also that stos has the l suffix to make it move longwords.
  103.      : /* no output registers */

  104. Well, there aren't any in this function.
  105.      : "c" (count), "a" (fill_value), "D" (dest)

  106. Here we load ecx with count, eax with fill_value, and edi with dest. Why make GCC do it instead of doing it ourselves? Because GCC, in its register allocating, might be able to arrange for, say, fill_value to already be in eax. If this is in a loop, it might be able to preserve eax thru the loop, and save a movl once per loop.
  107.      : "%ecx", "%edi" );

  108. And here's where we specify to GCC, "you can no longer count on the values you loaded into ecx or edi to be valid." This doesn't mean they will be reloaded for certain. This is the clobberlist.
  109. Seem funky? Well, it really helps when optimizing, when GCC can know exactly what you're doing with the registers before and after. It folds your assembly code into the code it's generates (whose rules for generation look remarkably like the above) and then optimizes. It's even smart enough to know that if you tell it to put (x+1) in a register, then if you don't clobber it, and later C code refers to (x+1), and it was able to keep that register free, it will reuse the computation. Whew.

  110. Here's the list of register loading codes that you'll be likely to use:

  111. a        eax
  112. b        ebx
  113. c        ecx
  114. d        edx
  115. S        esi
  116. D        edi
  117. I        constant value (0 to 31)
  118. q,r      dynamically allocated register (see below)
  119. g        eax, ebx, ecx, edx or variable in memory
  120. A        eax and edx combined into a 64-bit integer (use long longs)

  121. Note that you can't directly refer to the byte registers (ah, al, etc.) or the word registers (ax, bx, etc.) when you're loading this way. Once you've got it in there, though, you can specify ax or whatever all you like.
  122. The codes have to be in quotes, and the expressions to load in have to be in parentheses.

  123. When you do the clobber list, you specify the registers as above with the %. If you write to a variable, you must include "memory" as one of The Clobbered. This is in case you wrote to a variable that GCC thought it had in a register. This is the same as clobbering all registers. While I've never run into a problem with it, you might also want to add "cc" as a clobber if you change the condition codes (the bits in the flags register the jnz, je, etc. operators look at.)

  124. Now, that's all fine and good for loading specific registers. But what if you specify, say, ebx, and ecx, and GCC can't arrange for the values to be in those registers without having to stash the previous values. It's possible to let GCC pick the register(s). You do this:

  125. asm ("leal (%1,%1,4), %0"
  126.      : "=r" (x)
  127.      : "0" (x) );

  128. The above example multiplies x by 5 really quickly (1 cycle on the Pentium). Now, we could have specified, say eax. But unless we really need a specific register (like when using rep movsl or rep stosl, which are hardcoded to use ecx, edi, and esi), why not let GCC pick an available one? So when GCC generates the output code for GAS, %0 will be replaced by the register it picked.
  129. And where did "q" and "r" come from? Well, "q" causes GCC to allocate from eax, ebx, ecx, and edx. "r" lets GCC also consider esi and edi. So make sure, if you use "r" that it would be possible to use esi or edi in that instruction. If not, use "q".

  130. Now, you might wonder, how to determine how the %n tokens get allocated to the arguments. It's a straightforward first-come-first-served, left-to-right thing, mapping to the "q"'s and "r"'s. But if you want to reuse a register allocated with a "q" or "r", you use "0", "1", "2"... etc.

  131. You don't need to put a GCC-allocated register on the clobberlist as GCC knows that you're messing with it.

  132. Now for output registers.

  133. asm ("leal (%1,%1,4), %0"
  134.      : "=r" (x_times_5)
  135.      : "r" (x) );

  136. Note the use of = to specify an output register. You just have to do it that way. If you want 1 variable to stay in 1 register for both in and out, you have to respecify the register allocated to it on the way in with the "0" type codes as mentioned above.
  137. asm ("leal (%0,%0,4), %0"
  138.      : "=r" (x)
  139.      : "0" (x) );

  140. This also works, by the way:
  141. asm ("leal (%%ebx,%%ebx,4), %%ebx"
  142.      : "=b" (x)
  143.      : "b" (x) );

  144. 2 things here:
  145. Note that we don't have to put ebx on the clobberlist, GCC knows it goes into x. Therefore, since it can know the value of ebx, it isn't considered clobbered.
  146. Notice that in extended asm, you must prefix registers with %% instead of just %. Why, you ask? Because as GCC parses along for %0's and %1's and so on, it would interpret %edx as a %e parameter, see that that's non-existent, and ignore it. Then it would bitch about finding a symbol named dx, which isn't valid because it's not prefixed with % and it's not the one you meant anyway.
  147. Important note: If your assembly statement must execute where you put it, (i.e. must not be moved out of a loop as an optimization), put the keyword volatile after asm and before the ()'s. To be ultra-careful, use
  148. __asm__ __volatile__ (...whatever...);

  149. However, I would like to point out that if your assembly's only purpose is to calculate the output registers, with no other side effects, you should leave off the volatile keyword so your statement will be processed into GCC's common subexpression elimination optimization.
  150. Some useful examples
  151. #define disable() __asm__ __volatile__ ("cli");

  152. #define enable() __asm__ __volatile__ ("sti");

  153. Of course, libc has these defined too.
  154. #define times3(arg1, arg2) \
  155. __asm__ ( \
  156.   "leal (%0,%0,2),%0" \
  157.   : "=r" (arg2) \
  158.   : "0" (arg1) );

  159. #define times5(arg1, arg2) \
  160. __asm__ ( \
  161.   "leal (%0,%0,4),%0" \
  162.   : "=r" (arg2) \
  163.   : "0" (arg1) );

  164. #define times9(arg1, arg2) \
  165. __asm__ ( \
  166.   "leal (%0,%0,8),%0" \
  167.   : "=r" (arg2) \
  168.   : "0" (arg1) );

  169. These multiply arg1 by 3, 5, or 9 and put them in arg2. You should be ok to do:
  170. times5(x,x);

  171. as well.
  172. #define rep_movsl(src, dest, numwords) \
  173. __asm__ __volatile__ ( \
  174.   "cld\n\t" \
  175.   "rep\n\t" \
  176.   "movsl" \
  177.   : : "S" (src), "D" (dest), "c" (numwords) \
  178.   : "%ecx", "%esi", "%edi" )

  179. Helpful Hint: If you say memcpy() with a constant length parameter, GCC will inline it to a rep movsl like above. But if you need a variable length version that inlines and you're always moving dwords, there ya go.
  180. #define rep_stosl(value, dest, numwords) \
  181. __asm__ __volatile__ ( \
  182.   "cld\n\t" \
  183.   "rep\n\t" \
  184.   "stosl" \
  185.   : : "a" (value), "D" (dest), "c" (numwords) \
  186.   : "%ecx", "%edi" )

  187. Same as above but for memset(), which doesn't get inlined no matter what (for now.)

  188. #define RDTSC(llptr) ({ \
  189. __asm__ __volatile__ ( \
  190.         ".byte 0x0f; .byte 0x31" \
  191.         : "=A" (llptr) \
  192.         : : "eax", "edx"); })

  193. Reads the TimeStampCounter on the Pentium and puts the 64 bit result into llptr.

  194. The End
  195. "The End"?! Yah, I guess so.
  196. If you're wondering, I personally am a big fan of AT&T/UNIX syntax now. (It might have helped that I cut my teeth on SPARC assembly. Of course, that machine actually had a decent number of general registers.) It might seem weird to you at first, but it's really more logical than Intel format, and has no ambiguities.

  197. If I still haven't answered a question of yours, look in the Info pages for more information, particularly on the input/output registers. You can do some funky stuff like use "A" to allocate two registers at once for 64-bit math or "m" for static memory locations, and a bunch more that aren't really used as much as "q" and "r".

  198. Alternately, mail me, and I'll see what I can do. (If you find any errors in the above, please, e-mail me and tell me about it! It's frustrating enough to learn without buggy docs!) Or heck, mail me to say "boogabooga."

  199. It's the least you can do.



  200. --------------------------------------------------------------------------------

  201. Related Usenet posts:
  202. local labels
  203. fixed point multiplies

  204. --------------------------------------------------------------------------------
  205. Thanks to Eric J. Korpela <korpela@ssl.Berkeley.EDU> for some corrections.
  206. --------------------------------------------------------------------------------
  207. Have you seen the DJGPP2+Games Page? Probably.
  208. Page written and provided by Brennan Underwood.
  209. Copyright &copy; 1996 Brennan Underwood. Share and enjoy!
  210. Page created with vi, God's own editor.  
复制代码
回复 56# liuiang


    ...

by the way. i am search/learn/forgot it a hunders of times.
memo it:

论坛徽章:
0
58 [报告]
发表于 2012-12-04 19:02 |只看该作者
folklore 发表于 2012-10-27 22:57
我已经达到了这种程序:
面试的时候,大家都以为我在说谎。。。


看到这句 我笑了 哈哈哈

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
59 [报告]
发表于 2012-12-05 09:56 |只看该作者
回复 55# starwing83


“实时”这个词得先明确一下含义。
“实时”不等同于很快,也不等同于非常快,它等同与“保证足够快”。
重点在于两个,一个是“足够快”,对于不同的场合快慢要求是不一样的,需要明确指定响应时间的指标,对于火星车来说足够快的系统对于喷气机就有可能不够快。
还有一点是“保证”,目前大多数(如果不是全部)通用操作系统都没有办法保证任何一个动作一定在一个给定时间内完成,实时操作系统正是在这一点上区别于通用操作系统。

论坛徽章:
0
60 [报告]
发表于 2012-12-05 10:52 |只看该作者
支持楼主,我也对那人挺无语的。
上次我在链表排序那帖子里说算法简单,容易实现就是优点,居然被喷。

怀疑这种写书的到底有多少实际编码经验,
当由于进度安排,竞争对手压力逼得通宵加班编码,产品第二天就要放demo,还有一堆必须修补的bug时,哪还有心情研究c/c++的特殊用法,
编写直白易读,也便于同事理解和维护的,遵循小组编码规范的代码才是最重要的。

这是我工作中的感触,特别是上个月过了一段加班到半夜4,5点的噩梦一周后的切身体会,30多个人半夜等你修复bug。。。

可读性,可维护性,可测试性才是最重要的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP