通过包装非托管纤程_API_为_NET_实现代码协同.doc_第1页
通过包装非托管纤程_API_为_NET_实现代码协同.doc_第2页
通过包装非托管纤程_API_为_NET_实现代码协同.doc_第3页
通过包装非托管纤程_API_为_NET_实现代码协同.doc_第4页
通过包装非托管纤程_API_为_NET_实现代码协同.doc_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆薀肂芃葿螆羈节薁蕿袄芁芁螄螀莀莃薇聿荿蒅螂羅荿薈薅袁莈莇螁袇羄蒀蚄螃羃薂衿肁羃芁蚂羇羂莄袇袃羁蒆蚀蝿肀薈蒃肈聿芈蚈羄肈蒀蒁羀肇薃螇袆肇节薀螂肆莅螅肁肅蒇薈羇肄蕿螃袃膃艿薆螈膂莁螂蚄膁薄薄肃膁芃袀罿膀莆蚃袅腿蒈袈螁膈薀蚁肀芇芀蒄羆芆莂虿袂芅蒄蒂螈芅膄蚈螄芄莆 本文假设您熟悉托管 C+ 和 .NET下载本文的代码: CoroutinesinNET.exe (135KB) 摘要代码协同是很多编程语言(包括 CLU、Scheme、Python、Ruby 和 ICON)的一种强大功能。代码协同可以节省处理器开销并减少冗余,因为通过它们可以中途停止过程的执行,返回值,然后恰好从该过程停止执行的位置继续执行。本文说明了如何通过使用纤程 API 和 C+ 的托管扩展为 .NET Framework 实现代码协同,以及如何容易地将它们与其他兼容 .NET 的语言一起使用。本文还说明了如何老练地使用运行库宿主以便在单个 OS 线程中运行多个托管线程。本页内容代码协同和 .NET Framework纤程和线程实现详细信息生成器和树匹配示例小结纤程 可以从 32 位版本的 Windows 中使用的轻量级线程处理对象 在很多方案中都很有用。由于线程是宝贵资源,因此您有时不希望将整个 OS 线程专门用于执行简单的任务。通过纤程,可以比线程更严密地控制任务的调度,因为是您而不是 OS 负责管理它们。由于它们具有较少的开销,因此当您切换上下文时,它们还更加快速。此外,因为是由您控制纤程,所以对于它们而言,通常可以更容易地跟踪同步问题。代码协同是一个类似于纤程的、基于代码的概念,它已经在多个现代语言(如 CLU、Scheme、Python、Ruby 和 ICON)中实现。简单说来,代码协同是一种方法,它可以在执行过程中停止并且向调用方提供值,而无须返回程序流。由于代码协同和纤程是并行的概念,因此它们两个可以相互补充。在 Microsoft.NET Framework 下面,当前未以本机方式实现代码协同。(有关方面计划在将来发布 C# 版本。)但是,通过一点儿聪明的涉及到 Win32? 纤程 API 和 C+ 的托管扩展的编码工作,可以现在创建自己的代码协同库并且充分利用这一高级编程概念。可以将代码协同视为具有以下特点的方法:它们不返回到调用方,而是在处理中途停止执行,并且向调用方输出一个值。代码协同下一次被调用时,将从它上次停止执行的位置继续执行,直到输出另外一个值。例如,下面是一个对数组元素进行循环访问的小程序,它没有使用代码协同: class Iter public object Next() return arrayndx+; object array = new object 1, 2, 3, 4; int ndx;该代码循环访问的数组以及该数组的当前索引都是 Iter 类的字段。Next 方法返回数组的下一个元素。如果语言支持代码协同,则可以按如下方式编写相同的程序: class CorIter public void Next() object array = new object 1, 2, 3, 4; for(int ndx = 0; true; +ndx) Yield(arrndx); 这里需要注意的是,每当 Next 方法被调用时,它不是返回,而是保存它的当前执行状态(局部变量,如 array、ndx,以及下一条中间语言指令),并且调用 Yield 向调用方提供数组的下一个元素。该方法第一次被调用时,索引为 0,并且函数输出数组的第一个元素。当该方法随后被调用时,将从它上次停止执行的位置继续执行,递增索引并输出下一个元素。在这样一个价值不大的示例中,代码协同实际上并没有完成什么工作。但是,如果需要编写一个对二进制树进行顺序遍历的递归方法,以便逐个返回节点,会怎样呢?如果没有代码协同,这将很难实现。您或者必须手动移除递归并编写一个与 C+ 标准模板库中类似的迭代程序,或者需要在遇到每个节点时求助于使用回调。这两种选择都为程序员带来了负担。此外,第一种选择为实现迭代程序的编码者造成了更多的工作,而回调选择则给用户带来了它自己的问题。代码协同在语言中的出现是上述两种选择的一种方便的替代选择,因为通过它们可以在遇到节点时输出节点。在 Streamlining DOM XML processing with Python,您可以看到代码协同的类似用法 使用代码协同处理 XML DOM。Netscape () 中的 State Threads 库用 C 并通过 setjmp 和 longjmp 调用实现了代码协同。这两个代码协同示例还说明了 Python 生成器的概念:它们在被调用时将输出数组或二进制树的下一个值。使用代码协同,可以从 C# 内部通过简单的 foreach 语句枚举二进制树的节点: foreach(Node node in tree) / process the node代码协同的真正优点之一是,如果认为不需要进行其余计算,则可以中止代码协同。例如,为了了解两棵树是否按照相同顺序包含叶子(边缘匹配),我可以创建一个代码协同以输出第一棵树的叶子,并且创建另外一个代码协同以输出第二棵树的叶子。一旦我找到叶子不匹配的位置,我就可以中止这两个代码协同并且避免遍历这两棵树的其余节点。代码协同和 .NET Framework当我在 .NET Framework 中实现代码协同时,我做出了一些重大的设计和实现决策。在表示层,呈现给用户的接口应当非常干净(类似于其他语言中的接口)。用户应当始终能够中止代码协同。代码协同绝不应该导致应用程序中止,即使它生成了未被捕获的异常。在实现层,我使用 Win32 纤程 API 实现代码协同,因为公共语言运行库 (CLR) 没有提供创建独立的执行途径或者保存当前执行状态然后继续执行的方式。因为存在额外的资源开销,所以我决定不使用线程来实现代码协同。我还希望确保代码协同之间的切换不会在 CLR 内部导致任何问题,并且能够正确地清理内部 CLR 状态。我使用 C+ 的托管扩展来进行核心实现,因为通过它可以容易地在托管代码和非托管代码之间进行切换。同时,正像我稍后将解释的那样,我必须从非托管代码中挂钩 CLR 宿主,以通知运行库存在纤程。返回页首纤程和线程可以将 Windows NT 中的纤程视为必须手动调度的轻量线程。当创建纤程时,将向其传递一个纤程启动函数。然后,OS 为其分配一个单独的堆栈,并且将执行设置为从该纤程启动函数开始。要调度该纤程,您需要手动切换到该纤程。OS 保存当前正在运行的纤程的执行状态,然后开始执行新纤程。当该纤程切换到另一个纤程时,它的执行状态将以类似的方式保存,以便它稍后可以继续执行。在相同线程中可以调度很多个纤程,并且纤程还可以在线程之间移动。如果当前正在运行的纤程退出,则运行该纤程的线程也将退出。Platform SDK 文档详细解释了纤程(参阅 Fibers)。每个纤程都具有单独的堆栈和寄存器组。如果纤程正在运行托管代码,则可以保存纤程的托管执行状态,将程序控制传递给调用它的其他托管纤程(让渡),并且稍后恢复该状态。这就是在 .NET Framework 中将代码协同作为纤程加以实现的方法。我创建了一个名为 Fiber 的类,该类包含一个名为 Run 的抽象方法以及图 1 中显示的方法。Fiber 构造函数将执行设置为从调用抽象方法 Run 的函数开始。对 Resume 方法的调用将切换到该纤程,而该纤程又会调用 Run。代码协同从 Fiber 类继承,并且提供了 Run 方法的实现。在 Run 方法以及它所调用的其他方法中,代码协同让渡到前面的纤程。为了向该类中添加一些语法成分,我创建了一个名为 Coroutine 的委托,它包装了 Fiber 对象的 Resume 方法。我还在 Fiber 类中添加了一个隐式转换运算符: public _delegate System:Object* Coroutine();static Coroutine* op_Implicit(Fiber *obj) return new Coroutine(obj, &Fiber:Resume);使用 Fiber 类和该 Coroutine 委托,现在可以将循环访问数组的代码编写为: class CorIter : Fiber protected override void Run() object array = new object 1, 2, 3, 4; for(int ndx = 0; true; +ndx) Yield(arrndx); Coroutine next = new CorIter();Object o = next();每次调用下一个代码协同时,纤程都将恢复运行,并且执行从它上次停止时的状态继续。当纤程输出下一个数组元素时,相应的值就被立即传回给调用纤程。 返回页首实现详细信息在我详细解释 Fiber 类的代码之前,让我们回顾一下纤程和 CLR 之间的交互。起初,我试图直接从 .NET Framework 内部使用纤程,并为此花费了很大力气(尤其是在解决异常处理问题时)。然后我发现,像 .NET 异常处理机制一样,平台抽象层 (PAL) 和运行库大量使用了线程本地存储区 (TLS)。托管线程的异常处理程序列表存储在 TLS 槽中。有关 PAL 的详细信息,请参阅 Rotor:Shared Source CLI Provides Source Code for a FreeBSD Implementation of .NET。由于运行托管代码的纤程全部存在于相同线程中,因此在它们之间切换会对“托管”纤程上的异常处理程序造成问题。为了避免这一问题,我从非托管代码中挂钩了 CLR 宿主,并且使用四个未公开的 API 告诉运行库存在纤程,并且恰好在纤程之间切换之前通知它。以下是绑定到 CLR 宿主的静态构造函数: #pragma unmanagedICorRuntimeHost *corhost;void initialize_corhost() CorBindToCurrentRuntime(0, CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (void*) &corhost);#pragma managedstatic Fiber() initialize_corhost(); 下面显示了纤程构造函数和非托管纤程启动函数: Fiber() : retval(0), state(FiberCreated) void *objptr = (void*) GCHandle:op_Explicit(GCHandle:Alloc(this); fiber = CreateFiber(0, unmanaged_fiberproc, objptr);Fiber 对象的构造函数创建一个新纤程,该纤程在被调度后将立即开始执行 unmanaged_fiberproc 函数。在创建纤程时,Windows 允许您向纤程过程传递上下文信息。当纤程被调度时,它可以访问传递给它的信息。构造函数将指向 Fiber 对象的指针传递给非托管函数。由于不可能将托管指针直接传递给非托管代码,因此我使用 System:Runtime:InteropServices 命名空间中的 GCHandle 类获得指向托管 Fiber 对象的非托管指针(参见图 2)。 现在讨论棘手的部分。一旦我切换到该纤程并且非托管代码开始执行,我就需要向运行库发出有关刚刚创建的纤程的警告。未公开的函数 ICorRuntimeHost:CreateLogicalThread 告诉运行库设置托管线程(包括它自己的异常列表以及该纤程的 CLR 内部的其他数据)。这意味着对于每个纤程,都有一个相对应的托管线程。由于可以在同一 OS 线程上调度很多个纤程,因此这意味着多个托管线程可以在同一 OS 线程上运行。而且,因为稍后可以在另外一个 OS 线程上调度纤程,所以托管线程可以在不同的 OS 线程之间移动。可以通过本文的代码下载获得的示例应用程序 threads.cs 演示了这一概念(参见位于本文顶部的链接)。然后,非托管函数调用托管 fibermain 函数,并向其传递指向托管 Fiber 对象的指针。一旦 fibermain 返回,CLR 就不相干了。控制返回到非托管代码,我在此删除了我为该纤程创建的托管线程状态。然后,我切换回最后一次调度该纤程的纤程。托管 fibermain 函数只是获得 Fiber 对象并调用它的私有 main 方法: void* main() state = FiberRunning; try Run(); catch(System:Object *x) System:Console:Error-WriteLine( SnFIBERS.DLL: main Caught 0, x); state = FiberStopped; retval = 0; return previousfiber;Main 方法将纤程的状态设置为“正在运行”,并且设置一个异常处理程序以捕获任何异常。与 C# 中不同的是,托管 C+ 使我可以捕获不是派生自 Exception 类的异常。当我实现 Dispose 方法时,我将很好地利用这一功能。Run 可以正常返回或产生异常。在任一情况下,fibermain 都将获得控制,将状态设置为“停止”,并且返回最后一次调度该纤程的纤程。 在托管代码中,用户可以使用 Resume 和 Yield 方法在纤程之间切换。正如前面说明的那样,在纤程之间切换之前,需要通知 CLR。在进行 OS 级别 SwitchToFiber 之前,您必须告诉 CLR 保存当前正在运行的纤程的托管线程状态。正如您可以看到的那样,非托管函数 CorSwitchToFiber 完成这一工作: #pragma unmanagedvoid CorSwitchToFiber(void *fiber) DWORD *cookie; corhost-SwitchOutLogicalThreadState(&cookie); SwitchToFiber(fiber); corhost-SwitchInLogicalThreadState(cookie);CorSwitchToFiber 使用 ICorRuntimeHost:SwitchOutLogicalThreadState 方法在一个局部变量中保存线程状态,该方法存在于共享源 CLI 中(请记住,每个纤程都具有它自己的堆栈)。在保存状态之后,它将完成 OS 级别纤程切换。稍后,当切换到该纤程中时,将通过 Yield 或 Resume 还原 CLR 线程状态: System:Object* Resume() if(!fiber | state = FiberStopped) return 0; previousfiber = GetCurrentFiber(); CorSwitchToFiber(fiber); return retval;Resume 方法首先检查该纤程是否已经停止;如果尚未停止,则将 previousfiber 字段设置为当前正在运行的纤程并且进行 CorSwitchToFiber。 Yield 可以从 Run(它由代码协同实现)中或者从 Run 调用的方法中调用。Yield 切换到调度当前纤程的纤程,向其传递要输出的值,如以下代码中所示: _gc private struct StopFiber ;void Yield(System:Object *obj) retval = obj; CorSwitchToFiber(previousfiber); if(state = FiberStopPending) throw new StopFiber;Yield 设置 retval 字段并切换到上一个纤程(该纤程在对 Resume 的调用中暂停),并准备好执行 return retval 语句。请注意,不需要使用同步原语,原因是纤程被协同调度并且在同一线程上运行。如果 Run 只是返回而没有输出值,或者如果存在异常,则从 fibermain 中返回空值。 该 Yield 实现中保留的唯一的代码片段是对 FiberStopPending 进行的检查以及 StopFiber 的产生。我在设计时注意的事项之一是,可以中止代码协同并且丢弃它的剩余计算。不能简单地删除纤程,原因是 CLR 仍将保留该纤程的一些线程和执行状态信息。因为我需要非托管纤程启动过程获得控制(以便它可以删除为该纤程创建的 CLR 线程状态),所以我实现了 IDisposable:Dispose 方法: void Dispose() if(state = FiberRunning) previousfiber = GetCurrentFiber(); state = FiberStopPending; CorSwitchToFiber(fiber); DeleteFiber(fiber);Dispose 首先检查该纤程是否已经运行至完成。如果没有,它会将状态设置为 FiberStopPending 并切换到该纤程。因为该纤程运行得更早一些,所以它显然已经让渡。因此,Yield 就做好了执行以下语句的所有准备: if(state = FiberStopPending) throw new StopFiber;由于该异常不是派生自 Exception 类,因此无法从 C# 中捕获它,结果它被传播到调用 run 的 main 方法中。正如先前说明的那样,main 方法将纤程状态设置为“停止”,并且还会清除 retval。这样,控制就干净地返回到非托管纤程函数,而该函数将删除该纤程的 CLR 线程状态,并且切换回调用 Dispose 的纤程。 由于 CLR 在控制返回到非托管纤程启动函数后不再相干,因此我可以确保该纤程的内部 CLR 状态已经被正确清理。但是,使用异常(派生自 System.Object)来确保正确清理会给该类的使用施加一个小的限制。如果是从与 .NET Framework 兼容并且支持对不是派生自 Exception 类的异常进行捕获的语言中使用该实现,则重写的 Run 不应当具有一般性的 catch 子句。返回页首生成器和树匹配示例既然已经在 C+ 的托管扩展中完成了所有困难的工作,那么我就可以从其他语言中使用代码协同的威力了。我使用了 Dorai Sitaram 撰写的“Teach Yourself Scheme in Fixnum Days”中的树匹配示例,并且用 C# 实现了它。正像您将看到的那样,编写一个生成器以枚举树的叶子也很容易。如果两棵树的叶子具有相同的顺序,则无论深度如何,这两棵树都具有匹配的边缘,如图 3 所示。图 3 两棵树要在不使用代码协同的情况下了解边缘是否匹配,我必须通过遍历它们并将它们的叶子放在列表或数组中将这两棵树扁平化。之后,我可以遍历这两个列表,以便了解它们是否匹配。即使第一对叶子不匹配,我也已经引起了完全遍历每棵树以将其扁平化的处理开销。遍历第一棵树的代码协同可以在遇到每个叶子时输出它。第二个代码协同可以输出第二棵树的叶子。当第一次出现两个树的叶子不匹配的情况时,计算完成,并且两个代码协同都被中止。下面的代码(它使用了“访问者”设计模式)说明了这一点: interface TreeVisitor void Visit(Branch branch); void Visit(Leaf leaf);interface Tree void Accept(TreeVisitor visitor);该代码使用了一个名为 Tree 的接口,该接口带有一个接受 TreeVisitor 的方法。Branch 和 Leaf 类实现了 Tree 接口。Branch 是一个递归数据类型,它具有 Tree 类型的左节点和右节点,其中任一个节点都可以是另外一个 Branch 或 Leaf,如下所示: class Branch : Tree public Branch(Tree l, Tree r) left = l; righ

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论