<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>琥珀春秋 &#187; program</title>
	<atom:link href="http://amberlife.net/category/program/feed/" rel="self" type="application/rss+xml" />
	<link>http://amberlife.net</link>
	<description>又一个 WordPress Blog</description>
	<lastBuildDate>Sat, 17 Jul 2010 13:36:16 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>豆瓣url脑图分析。</title>
		<link>http://amberlife.net/2010/07/%e8%b1%86%e7%93%a3url%e8%84%91%e5%9b%be%e5%88%86%e6%9e%90%e3%80%82/</link>
		<comments>http://amberlife.net/2010/07/%e8%b1%86%e7%93%a3url%e8%84%91%e5%9b%be%e5%88%86%e6%9e%90%e3%80%82/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 02:06:17 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>
		<category><![CDATA[软件工程]]></category>

		<guid isPermaLink="false">http://amberlife.net/?p=227</guid>
		<description><![CDATA[


豆瓣url分析图

关于豆瓣的一个url分析，保存一份，供以后在分析
]]></description>
			<content:encoded><![CDATA[<div class="mceTemp">
<dl id="attachment_226" class="wp-caption alignnone" style="width: 210px;">
<dt class="wp-caption-dt"><img class="size-medium wp-image-226" title="douban_url" src="http://amberlife.net/wp-content/uploads/2010/07/douban_url1-200x300.png" alt="豆瓣url分析图" width="200" height="300" /></dt>
<dd class="wp-caption-dd">豆瓣url分析图</dd>
</dl>
<p>关于豆瓣的一个url分析，保存一份，供以后在分析</p></div>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2010/07/%e8%b1%86%e7%93%a3url%e8%84%91%e5%9b%be%e5%88%86%e6%9e%90%e3%80%82/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>01背包问题-回溯法-C语言实现。</title>
		<link>http://amberlife.net/2010/05/01%e8%83%8c%e5%8c%85%e9%97%ae%e9%a2%98-%e5%9b%9e%e6%ba%af%e6%b3%95-c%e8%af%ad%e8%a8%80%e5%ae%9e%e7%8e%b0%e3%80%82/</link>
		<comments>http://amberlife.net/2010/05/01%e8%83%8c%e5%8c%85%e9%97%ae%e9%a2%98-%e5%9b%9e%e6%ba%af%e6%b3%95-c%e8%af%ad%e8%a8%80%e5%ae%9e%e7%8e%b0%e3%80%82/#comments</comments>
		<pubDate>Fri, 14 May 2010 03:10:15 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>
		<category><![CDATA[数据结构]]></category>
		<category><![CDATA[回溯法 01背包问题]]></category>

		<guid isPermaLink="false">http://amberlife.net/?p=212</guid>
		<description><![CDATA[01背包问题-回溯法

#include &#60;stdio .h&#62;
#include &#60;stdlib .h&#62;
&#160;
int n=5,c=10;
int value&#91;5&#93;=&#123;6,3,5,4,6&#125;;
int weight&#91;5&#93;=&#123;2,2,6,5,4&#125;;
int cv&#91;5&#93;=&#123;0,0,0,0,0&#125;;
int bv&#91;5&#93;=&#123;0,0,0,0,0&#125;;
int cw=0;
int curv = 0 ;
int bestv =0 ;
void output&#40;&#41;
&#123;
   int i =0;
   for&#40;i; i&#60;n ; i++&#41;
     printf&#40;&#34;%d &#34;,bv&#91;i&#93;&#41;;
   printf&#40;&#34;%d&#34;,bestv&#41;;     
&#125;
&#160;
void trackback&#40;int i&#41;
&#123;
     int j;
    [...]]]></description>
			<content:encoded><![CDATA[<p>01背包问题-回溯法</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio .h&gt;</span>
<span style="color: #339933;">#include &lt;stdlib .h&gt;</span>
&nbsp;
<span style="color: #993333;">int</span> n<span style="color: #339933;">=</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span>c<span style="color: #339933;">=</span><span style="color: #0000dd;">10</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> value<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> weight<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> cv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> bv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> cw<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> curv <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span> <span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> bestv <span style="color: #339933;">=</span><span style="color: #0000dd;">0</span> <span style="color: #339933;">;</span>
<span style="color: #993333;">void</span> output<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
   <span style="color: #993333;">int</span> i <span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span>i<span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span>n <span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
     <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d &quot;</span><span style="color: #339933;">,</span>bv<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d&quot;</span><span style="color: #339933;">,</span>bestv<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>     
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> trackback<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
     <span style="color: #993333;">int</span> j<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>i<span style="color: #339933;">&gt;=</span>n<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
         <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>bestv<span style="color: #339933;">&lt;</span>curv <span style="color: #009900;">&#41;</span> 
        <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>j<span style="color: #339933;">&lt;</span>n<span style="color: #339933;">;</span>j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
                bv<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> cv<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> 
            bestv <span style="color: #339933;">=</span> curv<span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> 
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">else</span>
    <span style="color: #009900;">&#123;</span>
         <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>cw <span style="color: #339933;">+</span> weight<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">&lt;=</span>c<span style="color: #009900;">&#41;</span>
         <span style="color: #009900;">&#123;</span>
          cv<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span> 
          cw <span style="color: #339933;">+=</span>weight<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
          curv<span style="color: #339933;">+=</span> value<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
          trackback<span style="color: #009900;">&#40;</span>i<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
          cw <span style="color: #339933;">-=</span>weight<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
          curv<span style="color: #339933;">-=</span> value<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
          <span style="color: #009900;">&#125;</span>
          cv<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
          trackback<span style="color: #009900;">&#40;</span>i<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>argv<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  trackback<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  output<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  system<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;PAUSE&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
  <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></curv></n></stdlib></stdio></pre>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2010/05/01%e8%83%8c%e5%8c%85%e9%97%ae%e9%a2%98-%e5%9b%9e%e6%ba%af%e6%b3%95-c%e8%af%ad%e8%a8%80%e5%ae%9e%e7%8e%b0%e3%80%82/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>北大ACM（PKU JudgeOnline）题目分类【转载】</title>
		<link>http://amberlife.net/2010/02/%e5%8c%97%e5%a4%a7acm%ef%bc%88pku-judgeonline%ef%bc%89%e9%a2%98%e7%9b%ae%e5%88%86%e7%b1%bb%e3%80%90%e8%bd%ac%e8%bd%bd%e3%80%91/</link>
		<comments>http://amberlife.net/2010/02/%e5%8c%97%e5%a4%a7acm%ef%bc%88pku-judgeonline%ef%bc%89%e9%a2%98%e7%9b%ae%e5%88%86%e7%b1%bb%e3%80%90%e8%bd%ac%e8%bd%bd%e3%80%91/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 03:57:31 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>
		<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://amberlife.net/2010/02/%e5%8c%97%e5%a4%a7acm%ef%bc%88pku-judgeonline%ef%bc%89%e9%a2%98%e7%9b%ae%e5%88%86%e7%b1%bb%e3%80%90%e8%bd%ac%e8%bd%bd%e3%80%91/</guid>
		<description><![CDATA[1.搜索 //回溯
2.DP（动态规划）
3.贪心
4.图论 //Dijkstra、最小生成树、网络流
5.数论 //解模线性方程
6.计算几何 //凸壳、同等安置矩形的并的面积与周长
7.组合数学 //Polya定理
8.模拟
9.数据结构 //并查集、堆
10.博弈论

1、 排序
1423, 1694, 1723, 1727, 1763, 1788, 1828, 1838, 1840, 2201, 2376, 2377, 2380, 1318, 1877, 1928, 1971,
1974, 1990, 2001, 2002, 2092, 2379,
1002（需要字符处理，排序用快排即可） 1007（稳定的排序） 2159（题意较难懂） 2231 2371（简单排序）
2388（顺序统计算法） 2418（二叉排序树）
2、 搜索、回溯、遍历
1022 1111d 1118 1129 1190 1562 1564 1573 1655 2184 2225 2243 2312 2362 2378 2386
1010,1011,1018,1020,1054,1062,1256,1321,1363,1501，1650,1659,1664,1753,2078
,2083,2303,2310,2329
简单：1128, 1166, 1176, 1231, 1256, 1270, [...]]]></description>
			<content:encoded><![CDATA[<p>1.搜索 //回溯<br />
2.DP（动态规划）<br />
3.贪心<br />
4.图论 //Dijkstra、最小生成树、网络流<br />
5.数论 //解模线性方程<br />
6.计算几何 //凸壳、同等安置矩形的并的面积与周长<br />
7.组合数学 //Polya定理<br />
8.模拟<br />
9.数据结构 //并查集、堆<br />
10.博弈论</p>
<p><span id="more-202"></span></p>
<p>1、 排序<br />
1423, 1694, 1723, 1727, 1763, 1788, 1828, 1838, 1840, 2201, 2376, 2377, 2380, 1318, 1877, 1928, 1971,</p>
<p>1974, 1990, 2001, 2002, 2092, 2379,<br />
1002（需要字符处理，排序用快排即可） 1007（稳定的排序） 2159（题意较难懂） 2231 2371（简单排序）</p>
<p>2388（顺序统计算法） 2418（二叉排序树）<br />
2、 搜索、回溯、遍历<br />
1022 1111d 1118 1129 1190 1562 1564 1573 1655 2184 2225 2243 2312 2362 2378 2386</p>
<p>1010,1011,1018,1020,1054,1062,1256,1321,1363,1501，1650,1659,1664,1753,2078<br />
,2083,2303,2310,2329<br />
简单：1128, 1166, 1176, 1231, 1256, 1270, 1321, 1543, 1606, 1664, 1731, 1742, 1745, 1847, 1915, 1950,</p>
<p>2038, 2157, 2182, 2183, 2381, 2386, 2426,<br />
不易：1024, 1054, 1117, 1167, 1708, 1746, 1775, 1878, 1903, 1966, 2046, 2197, 2349,<br />
推荐：1011, 1190, 1191, 1416, 1579, 1632, 1639, 1659, 1680, 1683, 1691, 1709, 1714, 1753, 1771, 1826,</p>
<p>1855, 1856, 1890, 1924, 1935, 1948, 1979, 1980, 2170, 2288, 2331, 2339, 2340,1979（和迷宫类似） 1980（对剪枝</p>
<p>要求较高）<br />
3、 历法<br />
1008 2080 （这种题要小心）<br />
4、 枚举<br />
1012，1046， 1387， 1411， 2245， 2326， 2363， 2381，1054（剪枝要求较高），1650 （小数的精度问题</p>
<p>）<br />
5、 数据结构的典型算法<br />
容易：1182, 1656, 2021, 2023, 2051, 2153, 2227, 2236, 2247, 2352, 2395,<br />
不易：1145, 1177, 1195, 1227, 1661, 1834,<br />
推荐：1330, 1338, 1451, 1470, 1634, 1689, 1693, 1703, 1724, 1988, 2004, 2010, 2119, 2274, 1125(弗洛伊德算</p>
<p>法) ，2421（图的最小生成树）<br />
6、 动态规划<br />
1037 A decorative fence、<br />
1050 To the Max、<br />
1088 滑雪、<br />
1125 Stockbroker Grapevine、<br />
1141 Brackets Sequence、<br />
1159 Palindrome、<br />
1160 Post Office、<br />
1163 The Triangle、<br />
1458 Common Subsequence、<br />
1579 Function Run Fun、<br />
1887 Testing the CATCHER、<br />
1953 World Cup Noise、<br />
2386 Lake Counting<br />
7、 贪心<br />
1042, 1065, 1230, 1323, 1477, 1716, 1784,1328 1755（或用单纯形方法），2054，1017， 1328，1862， 1922</p>
<p>，2054， 2209， 2313， 2325， 2370。<br />
8、 模拟<br />
容易：1006, 1008, 1013, 1016, 1017, 1169, 1298, 1326, 1350, 1363, 1676, 1786, 1791, 1835, 1970, 2317,</p>
<p>2325, 2390,<br />
不易：1012, 1082, 1099, 1114, 1642, 1677, 1684, 1886,1281 1928 2083 2141 2015<br />
9、 递归<br />
1664<br />
10、字符串处理<br />
1488, 1598, 1686, 1706, 1747, 1748, 1750, 1760, 1782, 1790, 1866, 1888, 1896, 1951, 2003, 2121, 2141,</p>
<p>2145, 2159, 2337, 2359, 2372, 2406, 2408, 1016 1051 1126 1318 1572 1917 1936 2039 2083 2136 2271 2317</p>
<p>2330，2121 2403<br />
11、数论<br />
1006,1014,1023,1061,1152,1183,1730,2262<br />
12、几何有关的题目<br />
凸包：1113, 1228, 1794, 2007, 2187,1113 wall，2187 beauty contest<br />
容易：1319, 1654, 1673, 1675, 1836, 2074, 2137, 2318,<br />
不易：1685, 1687, 1696, 1873, 1901, 2172, 2333,<br />
13、任意精度运算、数字游戏、高精度计算<br />
1001 1023 1047 1060 1079 1131 1140 1142 1207 1220 1284 1289 1306 1316 1338 1405 1454 1503 1504</p>
<p>1519 1565 1650 1969 2000 2006 2081 2247 2262 2305 2316 2389 1001, 1220, 1405, 1503,1001（高精度乘法）</p>
<p>2413(高精度加法，还有二分查找)<br />
14、概率统计<br />
1037,1050<br />
15、小费用最大流、最大流<br />
2195 going home，2400 supervisor, supervisee，1087 a plug for UNIX，1149 PIGS，1273 drainage</p>
<p>ditches，1274 the perfect stall，1325 machine schedule，1459 power network，2239 selecting courses<br />
16、压缩存储的DP<br />
1038 bugs integrated inc，1185 炮兵阵地，2430 lazy cow<br />
17、最长公共子串（LCS）<br />
1080 human gene functions，1159 palindrome，1458 common subsequence，2192 zipper<br />
18、图论及组合数学<br />
2421 Constructing Roads、<br />
2369 Permutations、<br />
2234 Matches Game、<br />
2243 Knight Moves、<br />
2249 Binomial Showdown、<br />
2255 Tree Recovery、<br />
2084 Game of Connections、<br />
1906 Three powers、<br />
1833 排列、<br />
1850 Code、<br />
1562 Oil Deposits、<br />
1496 Word Index、<br />
1306 Combinations、<br />
1125 Stockbroker Grapevine、<br />
1129 Channel Allocation、<br />
1146 ID Codes、<br />
1095 Trees Made to Order、找规律<br />
2247 Humble Numbers、<br />
2309 BST、<br />
2346 Lucky tickets、<br />
2370 Democracy in danger、<br />
2365 Rope、<br />
2101 Honey and Milk Land<br />
2028 When Can We Meet?、<br />
2084 Game of Connections、<br />
1915 Knight Moves、<br />
1922 Ride to School、<br />
1941 The Sierpinski Fractal、<br />
1953 World Cup Noise、<br />
1958 Strange Towers of Hanoi、<br />
1969 Count on Canton、<br />
1806 Manhattan 2025、<br />
1809 Regetni、<br />
1844 Sum、<br />
1870 Bee Breeding、<br />
1702 Eva\&#8217;s Balance、<br />
1728 A flea on a chessboard、<br />
1604 Just the Facts、<br />
1642 Stacking Cubes、<br />
1656 Counting Black、<br />
1657 Distance on Chessboard、<br />
1662 CoIns、<br />
1663 Number Steps、<br />
1313 Booklet Printing、<br />
1316 Self Numbers、<br />
1320 Street Numbers、<br />
1323 Game Prediction、<br />
1338 Ugly Numbers、<br />
1244 Slots of Fun、<br />
1250 Tanning Salon、<br />
1102 LC-Display、<br />
1147 Binary codes、<br />
1013 Counterfeit Dollar、<br />
19、博弈类<br />
1067 取石子游戏、<br />
1740 A New Stone Game、<br />
2234 Matches Game、<br />
1082 Calendar Game 、<br />
2348 Euclid\&#8217;s Game、<br />
2413 How many Fibs?、<br />
2419 Forest<br />
20、简单、模拟题<br />
1001 Exponentiation 、<br />
1002 487-3279、<br />
1003 Hangover 、<br />
1701 Dissatisfying Lift、<br />
2301 Beat the Spread!、<br />
2304 Combination Lock、<br />
2328 Guessing Game、<br />
2403 Hay Points 、<br />
2406 Power Strings、<br />
2339 Rock, Scissors, Paper、<br />
2350 Above Average、<br />
2218 Does This Make Me Look Fat?、<br />
2260 Error Correction、<br />
2262 Goldbach\&#8217;s Conjecture、<br />
2272 Bullseye、<br />
2136 Vertical Histogram、<br />
2174 Decoding Task、<br />
2183 Bovine Math Geniuses、<br />
2000 Gold Coins、<br />
2014 Flow Layout、<br />
2051 Argus、<br />
2081 Calendar、<br />
1918 Ranking List、<br />
1922 Ride to School、<br />
1970 The Game、<br />
1972 Dice Stacking、<br />
1974 The Happy Worm、<br />
1978 Hanafuda Shuffle、<br />
1979 Red and Black、<br />
1617 Crypto Columns、<br />
1666 Candy Sharing Game、<br />
1674 Sorting by Swapping、<br />
1503 Integer Inquiry、<br />
1504 Adding Reversed Numbers、<br />
1528 Perfection、<br />
1546 Basically Speaking、<br />
1547 Clay Bully、<br />
1573 Robot Motion、<br />
1575 Easier Done Than Said?、<br />
1581 A Contesting Decision、<br />
1590 Palindromes、<br />
1454 Factorial Frequencies、<br />
1363 Rails、<br />
1218 THE DRUNK JAILER、<br />
1281 MANAGER、<br />
1132 Border、<br />
1028 Web Navigation、<br />
21、初等数学<br />
1003 Hangover、<br />
1045 Bode Plot、<br />
1254 Hansel and Grethel、<br />
1269 Intersecting Lines、<br />
1401 Factorial、<br />
1410 Intersection、<br />
2363 Blocks 、<br />
2365 Rope、<br />
2242 The Circumference of the Circle、<br />
2291 Rotten Ropes、<br />
2295 A DP Problem、<br />
2126 Factoring a Polynomial、<br />
2191 Mersenne Composite Numbers、<br />
2196 Specialized Four-Digit Numbers、<br />
1914 Cramer\&#8217;s Rule、<br />
1835 宇航员、<br />
1799 Yeehaa!、<br />
1607 Deck、<br />
1244 Slots of Fun、<br />
1269 Intersecting Lines、<br />
1299 Polar Explorer、<br />
1183 反正切函数的应用、<br />
22、匹配<br />
1274, 1422, 1469, 1719, 2060, 2239,<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
经典<br />
1011（搜索好题）<br />
1012（学会打表）<br />
1013<br />
1019（它体现了很多此类问题的特点）<br />
1050（绝对经典的dp）<br />
1088（dp好题）<br />
1157（花店，经典的dp）<br />
1163（怎么经典的dp那么多呀？？？）<br />
1328（贪心）<br />
1458（最长公共子序列）<br />
1647（很好的真题，考临场分析准确和下手迅速）<br />
1654（学会多边形面积的三角形求法）<br />
1655（一类无根树的dp问题）<br />
1804（逆序对）<br />
2084（经典组合数学问题）<br />
2187（用凸包求最远点对，求出凸包后应该有O(N)的求法，可我就是调不出来）<br />
2195（二分图的最佳匹配）<br />
2242（计算几何经典）<br />
2295（等式处理）<br />
2353（dp，但要记录最佳路径）<br />
2354（立体解析几何）<br />
2362（搜索好题）<br />
2410（读懂题是关键）<br />
2411（经典dp）<br />
趣味<br />
1067（很难的数学，但仔细研究，是一片广阔的领域）<br />
1147（有O(n)的算法，需要思考）<br />
1240（直到一棵树的先序和后序遍历，那么有几种中序遍历呢？dp）<br />
1426（是数论吗？错，是图论！）<br />
1648（别用计算几何，用整点这个特点绕过精度的障碍吧）<br />
1833（找规律）<br />
1844（貌似dp或是搜索，其实是道有趣的数学题）<br />
1922（贪心，哈哈）<br />
2231<br />
2305（不需要高精度噢）<br />
2328（要仔细噢）<br />
2356（数论知识）<br />
2359（约瑟夫问题变种）<br />
2392（有趣的问题）<br />
很繁的题<br />
1001<br />
1008<br />
1087（构图很烦，还有二分图的最大匹配）<br />
1128（USACO）<br />
1245<br />
1329<br />
1550（考的是读题和理解能力）<br />
1649（dp）<br />
2200（字符串处理+枚举）<br />
2358（枚举和避免重复都很烦）<br />
2361（仔细仔细再仔细）<br />
难题<br />
1014（数学证明比较难，但有那种想法更重要）<br />
1037（比较难的dp）<br />
1405（高精度算法也分有等级之分，不断改进吧）<br />
2002（不知道有没有比O(n^2*logn)更有的算法？）<br />
2054（极难，很强的思考能力）<br />
2085（组合数学）<br />
2414（dp，但要剪枝）<br />
2415（搜索）<br />
2423（计算几何+统计）<br />
多解题<br />
1002（可以用排序，也可以用统计的方法）<br />
1338（搜索和dp都可以）<br />
1664（搜索和dp都练一练吧）<br />
2082（这可是我讲的题噢）<br />
2352（桶排和二叉树都行）<br />
Note:<br />
1011: 很经典的剪支<br />
1014: 难在数学上<br />
1017: 严格的数学证明貌似不容易<br />
1021: 有点繁,考察对图形进行各种旋转的处理<br />
1083: 巧妙的思考角度<br />
1150: 分奇偶讨论,lg(n)算法<br />
1218: 三行就够了,虽然简单,但也有优劣之别<br />
1505: 二分加贪心<br />
1654: 做法也许很多吧,本人用有向面积做的<br />
1674: 计算圈的个数(算是graph 吧)<br />
1700: 数学证明不容易<br />
1742: O(m*n)的算法<br />
1863: 要耐心地慢慢写…<br />
1988: 并查集<br />
2051: 堆<br />
2078: 不难，但剪支可以做到很好<br />
2082::O(n),你想到了吗？<br />
2084: 卡特兰数<br />
2182: 线段树<br />
2195: 最小费用最大流<br />
2234: 经典博弈算法<br />
2236: 并查集<br />
2299: 二分思想<br />
2395: Kruskal 最小生成树的拓展<br />
2406: KMP<br />
2411: 用二进制串</p>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2010/02/%e5%8c%97%e5%a4%a7acm%ef%bc%88pku-judgeonline%ef%bc%89%e9%a2%98%e7%9b%ae%e5%88%86%e7%b1%bb%e3%80%90%e8%bd%ac%e8%bd%bd%e3%80%91/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>理解c#中的异步方法</title>
		<link>http://amberlife.net/2010/01/%e7%90%86%e8%a7%a3c%e4%b8%ad%e7%9a%84%e5%bc%82%e6%ad%a5%e6%96%b9%e6%b3%95/</link>
		<comments>http://amberlife.net/2010/01/%e7%90%86%e8%a7%a3c%e4%b8%ad%e7%9a%84%e5%bc%82%e6%ad%a5%e6%96%b9%e6%b3%95/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 11:52:47 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>
		<category><![CDATA[c#，多线程，异步]]></category>

		<guid isPermaLink="false">http://amberlife.net/?p=176</guid>
		<description><![CDATA[c#中构建多线程应用程序，不一定要通过System.Threading命名空间下的类来实现，通过delegate委托也能够实现多线程编程所需要的方式，（其实delegate就是利用CLR的ThreadPool来实现的，这个不再我们的讨论范围）。

先来说一下委托吧，通过当我们在应用程序中定义了一个委托后，其实在被编译成CIL后，就是一个类，我们可以通过ildasm.exe 这个程序来查看生成的CIL。
我们举个例子:

delegate  int   del &#40;string str1, string str2&#41;

del被编译后，生成的类的定义如下：

sealed class  del: System.MulticastDelegate
&#123;
	public del&#40;object target,uint functionAddress&#41;;
	public void Invoke&#40;string str1,string str2&#41;;
	public IAsyncResult BeginInvoke&#40;string str1,string str2,AsyncCallback cb ,object state&#41;;
	public int EndInvoke&#40;IAsyncResult result&#41;;
&#125;

生成的Invoke()方法用来调用被代理对象同步方式维护的方法，调用线程（应用程序的主线程）会一直等待，直到委托调用完成。在c#中，Invoke()不会被显式的调用，而是在同步方式下自动被触发。
下面我们来说说BeginInvoke方法和EndInvoke()方法，这两个方法是在利用委托来实现异步调用的关键。
在本例中BeginInvoke方法如下：

		IAsyncResult BeginInvoke&#40;string str1,string str2, AsyncCallback cb ,object state&#41;;

可以看到BeginInvoke方法返回IAsyncResult，参数列表中含有四个参数，前两个参数如同del委托中参数的定义，后两个参数System.AsyncCallback和System.Object类型的。
在本例中的EndInvoke方法如下：

int EndInvoke&#40;IAsyncResult result&#41;

EndInvoke方法返回int ，参数列表中含有一个参数，参数类型为IAsyncResult。在BeginInvoke方法和EndInvoke方法中，BeginInvoke方法中除了最后两个参数，前面的参数必须和之前定义的委托中的参数一样；EndInvoke方法的返回值必须和之前定义的委托的返回值一样。
借助上面定义的委托，我们写这样一个函数

int  stradd &#40;string str1,string str2&#41;
&#123;
	//仅仅为了测试一下异步方法的线程和调用线程是否是一致的。
	Console.WriteLine&#40;&#34;stradd thread id : &#34;,Thread.CurrentThread.GetHashCode&#40;&#41;&#41;;
	return str1.length+str2.length;
&#125;

下面定义一个主函数测试一下：

static void Main&#40;string&#91;&#93; args&#41;
&#123;
	Console.writeLine&#40;&#34;Main [...]]]></description>
			<content:encoded><![CDATA[<p>c#中构建多线程应用程序，不一定要通过System.Threading命名空间下的类来实现，通过delegate委托也能够实现多线程编程所需要的方式，（其实delegate就是利用CLR的ThreadPool来实现的，这个不再我们的讨论范围）。<br />
<span id="more-176"></span><br />
先来说一下委托吧，通过当我们在应用程序中定义了一个委托后，其实在被编译成CIL后，就是一个类，我们可以通过ildasm.exe 这个程序来查看生成的CIL。</p>
<p>我们举个例子:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #FF0000;">delegate</span>  <span style="color: #FF0000;">int</span>   del <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> str1, <span style="color: #FF0000;">string</span> str2<span style="color: #000000;">&#41;</span></pre></div></div>

<p>del被编译后，生成的类的定义如下：</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">sealed</span> <span style="color: #FF0000;">class</span>  del<span style="color: #008000;">:</span> <span style="color: #000000;">System</span>.<span style="color: #0000FF;">MulticastDelegate</span>
<span style="color: #000000;">&#123;</span>
	<span style="color: #0600FF;">public</span> del<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">object</span> target,<span style="color: #FF0000;">uint</span> functionAddress<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> Invoke<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> str1,<span style="color: #FF0000;">string</span> str2<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #0600FF;">public</span> IAsyncResult BeginInvoke<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> str1,<span style="color: #FF0000;">string</span> str2,AsyncCallback cb ,<span style="color: #FF0000;">object</span> state<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">int</span> EndInvoke<span style="color: #000000;">&#40;</span>IAsyncResult result<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>生成的Invoke()方法用来调用被代理对象同步方式维护的方法，调用线程（应用程序的主线程）会一直等待，直到委托调用完成。在c#中，Invoke()不会被显式的调用，而是在同步方式下自动被触发。<br />
下面我们来说说BeginInvoke方法和EndInvoke()方法，这两个方法是在利用委托来实现异步调用的关键。<br />
在本例中BeginInvoke方法如下：</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;">		IAsyncResult BeginInvoke<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> str1,<span style="color: #FF0000;">string</span> str2, AsyncCallback cb ,<span style="color: #FF0000;">object</span> state<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span></pre></div></div>

<p>可以看到BeginInvoke方法返回IAsyncResult，参数列表中含有四个参数，前两个参数如同del委托中参数的定义，后两个参数System.AsyncCallback和System.Object类型的。<br />
在本例中的EndInvoke方法如下：</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #FF0000;">int</span> EndInvoke<span style="color: #000000;">&#40;</span>IAsyncResult result<span style="color: #000000;">&#41;</span></pre></div></div>

<p>EndInvoke方法返回int ，参数列表中含有一个参数，参数类型为IAsyncResult。在BeginInvoke方法和EndInvoke方法中，BeginInvoke方法中除了最后两个参数，前面的参数必须和之前定义的委托中的参数一样；EndInvoke方法的返回值必须和之前定义的委托的返回值一样。</p>
<p>借助上面定义的委托，我们写这样一个函数</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #FF0000;">int</span>  stradd <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span> str1,<span style="color: #FF0000;">string</span> str2<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	<span style="color: #008080; font-style: italic;">//仅仅为了测试一下异步方法的线程和调用线程是否是一致的。</span>
	Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;stradd thread id : &quot;</span>,Thread.<span style="color: #0000FF;">CurrentThread</span>.<span style="color: #0000FF;">GetHashCode</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #0600FF;">return</span> str1.<span style="color: #0000FF;">length</span><span style="color: #008000;">+</span>str2.<span style="color: #0000FF;">length</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>下面定义一个主函数测试一下：</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">static</span> <span style="color: #0600FF;">void</span> Main<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> args<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	Console.<span style="color: #0000FF;">writeLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Main thread id :&quot;</span>,Thread.<span style="color: #0000FF;">CurrentThread</span>.<span style="color: #0000FF;">GetHashCode</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	del dd <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> del<span style="color: #000000;">&#40;</span>stradd<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	IAsyncResult result <span style="color: #008000;">=</span> dd.<span style="color: #0000FF;">BeginInvoke</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;hello &quot;</span>,<span style="color: #666666;">&quot;The another thread&quot;</span>,<span style="color: #0600FF;">null</span>,<span style="color: #0600FF;">null</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
	<span style="color: #008080; font-style: italic;">//EndInvoke方法阻塞调用线程，直到stradd方法运行结束</span>
	<span style="color: #FF0000;">int</span> len <span style="color: #008000;">=</span> dd.<span style="color: #0000FF;">EndInvoke</span><span style="color: #000000;">&#40;</span>result<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;the length of str1 + str2 ={0}&quot;</span>,len<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>运行后我们可以知道异步调用就是创建了一个次线程。<br />
通过上面的例子，我们可以看到一个异步调用的过程，但是，这样的调用对于多线程的要求，是毫无用处的，<br />
     endInvoke方法仍旧会阻塞主线程的运行。那么有没有好的方式来实现呢？我们想一下，如果能够在次线程还没有结束的时候，我们能够查看到次线程的运行的状态，在次线程还没有结束的时候，我们可以做主线程剩下的工作，这样的话，就不会让主线程一直在那里等待。</p>
<p>   为了实现这样的机制，我们先来看一个接口IAsyncResult,这个接口在异步方法中很常见，回顾一下刚才看到得东西，BeginInvoke方法的返回值<br />
EndInvoke方法的参数，都是这个接口。我们看一下这个接口的定义：</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">public</span> <span style="color: #FF0000;">interface</span>  IAsyncResult
<span style="color: #000000;">&#123;</span>
	<span style="color: #FF0000;">object</span> AsyncState<span style="color: #000000;">&#123;</span>get <span style="color: #008000;">;</span><span style="color: #000000;">&#125;</span>
	WaitHandle AsyncWaitHandle<span style="color: #000000;">&#123;</span>get<span style="color: #008000;">;</span><span style="color: #000000;">&#125;</span>
	<span style="color: #FF0000;">bool</span> CompletedSynchronously<span style="color: #000000;">&#123;</span>get<span style="color: #008000;">;</span><span style="color: #000000;">&#125;</span>
	<span style="color: #FF0000;">bool</span> IsCompleted<span style="color: #000000;">&#123;</span>get<span style="color: #008000;">;</span><span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>IAsyncResult提供了IsCompleted接口，使用这个属性，调用线程可以在调用EndInvoke方法之前，自动判断异步调用是否完成。如果完成，返回true；<br />
未完成返回false；</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">static</span> <span style="color: #0600FF;">void</span> Main<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> args<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	Console.<span style="color: #0000FF;">writeLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Main thread id :&quot;</span>,Thread.<span style="color: #0000FF;">CurrentThread</span>.<span style="color: #0000FF;">GetHashCode</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	del dd <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> del<span style="color: #000000;">&#40;</span>stradd<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	IAsyncResult result <span style="color: #008000;">=</span> dd.<span style="color: #0000FF;">BeginInvoke</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;hello &quot;</span>,<span style="color: #666666;">&quot;The another thread&quot;</span>,<span style="color: #0600FF;">null</span>,<span style="color: #0600FF;">null</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #0600FF;">while</span> <span style="color: #000000;">&#40;</span>result.<span style="color: #0000FF;">IsCompleted</span><span style="color: #000000;">&#41;</span>
	<span style="color: #000000;">&#123;</span>
		<span style="color: #008080; font-style: italic;">//做主线程接下来的工作。</span>
	<span style="color: #000000;">&#125;</span>
	<span style="color: #008080; font-style: italic;">//EndInvoke方法阻塞调用线程，直到stradd方法运行结束</span>
	<span style="color: #FF0000;">int</span> len <span style="color: #008000;">=</span> dd.<span style="color: #0000FF;">EndInvoke</span><span style="color: #000000;">&#40;</span>result<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;the length of str1 + str2 ={0}&quot;</span>,len<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>      通过这样的一种轮询机制，我们能够实现调用线程不会被阻塞，同时能保证第一时间获取次线程运行的结果，但仔细想过之后就会发现这种方式的笨拙，要不断的执行<br />
while循环中的内容，直到次线程完成。基于这一原因，IAsyncResult提供了AsyncWaitHandle属性实现更加灵活的控制。AsyncWaitHandle返回一个WaitHandle类型的实例<br />
该实例含有一个WaitOne的公共方法,查看msdn，我们看到，这个方法可以阻塞调用线程，直到WaitHandle收到信号。<br />
更改上面的main方法，如下所示：</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">static</span> <span style="color: #0600FF;">void</span> Main<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> args<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	Console.<span style="color: #0000FF;">writeLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Main thread id :&quot;</span>,Thread.<span style="color: #0000FF;">CurrentThread</span>.<span style="color: #0000FF;">GetHashCode</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	del dd <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> del<span style="color: #000000;">&#40;</span>stradd<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	IAsyncResult result <span style="color: #008000;">=</span> dd.<span style="color: #0000FF;">BeginInvoke</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;hello &quot;</span>,<span style="color: #666666;">&quot;The another thread&quot;</span>,<span style="color: #0600FF;">null</span>,<span style="color: #0600FF;">null</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #0600FF;">while</span> <span style="color: #000000;">&#40;</span><span style="color: #008000;">!</span>result. <span style="color: #0000FF;">AsyncWaitHandle</span>.<span style="color: #0000FF;">WaitOne</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">2000</span>，<span style="color: #0600FF;">true</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
	<span style="color: #000000;">&#123;</span>
		<span style="color: #008080; font-style: italic;">//做主线程接下来的工作。</span>
	<span style="color: #000000;">&#125;</span>
	<span style="color: #008080; font-style: italic;">//EndInvoke方法阻塞调用线程，直到stradd方法运行结束</span>
	<span style="color: #FF0000;">int</span> len <span style="color: #008000;">=</span> dd.<span style="color: #0000FF;">EndInvoke</span><span style="color: #000000;">&#40;</span>result<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;the length of str1 + str2 ={0}&quot;</span>,len<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>       使用WaitHandle.waitOne(2000,true),指定最长等待时间为秒，秒后如果AsyncWaitHandle未受到次线程结束的信号，返回false；否则返回true。<br />
       通过上述两种方式，我们发现一个共同点，就是调用线程(主线程)在询问次线程是否完成了，并且这种询问是一次又一次的进行，这种方式显的笨拙。如果当次线程结束的时候<br />
能够让他自己来通知主线程，说明自己结束了，这样的话，主线程就没有必要在花费时间来询问次线程，这样的方式显然更好理解。</p>
<p>       想要实现这样的一种方式，我们就必须来理解BeginInvoke的后两个参数，我们先来介绍AsyncCallback参数，这个参数是一个委托，默认值是null。只要提供了AsyncCallback对象<br />
当异步调用完成的时候，就会自动的调用AsyncCallback委托所指定的方法。AsyncCallback委托能够调用那些符合特定模式的方法，方法的签名如下所示：</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">void</span> AsyncCallbackMethod<span style="color: #000000;">&#40;</span>IAsyncResult iac<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span></pre></div></div>

<p>我们还用上面的例子，这次用次线程结束后调用AsyncCallback委托指定的方法这样的方式来实现.</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">static</span> <span style="color: #0600FF;">void</span> Main<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> args<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	Console.<span style="color: #0000FF;">writeLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Main thread id :&quot;</span>,Thread.<span style="color: #0000FF;">CurrentThread</span>.<span style="color: #0000FF;">GetHashCode</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	del dd <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> del<span style="color: #000000;">&#40;</span>stradd<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	IAsyncResult result <span style="color: #008000;">=</span> dd.<span style="color: #0000FF;">BeginInvoke</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;hello &quot;</span>,<span style="color: #666666;">&quot;The another thread&quot;</span>,<span style="color: #008000;">new</span> AsyncCallback<span style="color: #000000;">&#40;</span>complete<span style="color: #000000;">&#41;</span>,<span style="color: #0600FF;">null</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #008080; font-style: italic;">//做主线程接下来的工作</span>
<span style="color: #000000;">&#125;</span>
<span style="color: #0600FF;">void</span> complete <span style="color: #000000;">&#40;</span>IAsyncResult iac<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;The stradd method has completed。&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span><span style="color: #008080; font-style: italic;">//告诉了主线程，次线程已经工作结束了。</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>在这个例子中，会发现我们在主线程中，由于没有调用EndInvoke方法(调用这个方法，会阻塞主线程，那么就等于没有体现异步的优点) 我们无法得到stradd方法运算的结果。现在注意complete方法的参数IAsyncResult iac。(又一次碰到了这个接口，可见他是多么的重要)<br />
这是一个接口，我们没法直接使用它，在c#中存在一个实现了IAsyncResult接口的类AsyncResult。利用这个类，我们能够得到想要的结果。<br />
下面我们修改complete方法，如下所示：</p>
<pre lang="csharp>
void complete (IAsyncResult iac)
{
	AsyncResult ar = (AsyncResult)iac;
	del dd = (del)ar.AsyncDelegate;
	int len = dd.EndInvoke(iac);
	Console.WriteLine("the length of str1 + str2 ={0}",len);
	Console.WriteLine("The stradd method has completed。");//告诉了主线程，次线程已经工作结束了。
}
</pre>
<p>修改后，我们彻底完成了通过次线程通知主线程，来告知自己结束，这样一种异步调用的机制。<br />
看到这里，我们发现，在BeginInvoke中，最后一个参数我们始终没有提及，这个参数的类型是System.Object的，所以可以传入任意想要看到的类型。<br />
该参数允许从主线程传递额外的状态信息给AsyncCallback委托中的回调方法。<br />
我们定义个额外的类</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #FF0000;">class</span> Message
<span style="color: #000000;">&#123;</span>
	<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">string</span> msg <span style="color: #008000;">=</span> <span style="color: #666666;">&quot;一些额外的内容&quot;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span>
修改main方法如下：
<span style="color: #0600FF;">static</span> <span style="color: #0600FF;">void</span> Main<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> args<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	Console.<span style="color: #0000FF;">writeLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Main thread id :&quot;</span>,Thread.<span style="color: #0000FF;">CurrentThread</span>.<span style="color: #0000FF;">GetHashCode</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	del dd <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> del<span style="color: #000000;">&#40;</span>stradd<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	IAsyncResult result <span style="color: #008000;">=</span> dd.<span style="color: #0000FF;">BeginInvoke</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;hello &quot;</span>,<span style="color: #666666;">&quot;The another thread&quot;</span>,<span style="color: #008000;">new</span> AsyncCallback<span style="color: #000000;">&#40;</span>complete<span style="color: #000000;">&#41;</span>,<span style="color: #008000;">new</span> Message<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	<span style="color: #008080; font-style: italic;">//做主线程接下来的工作</span>
	Console.<span style="color: #0000FF;">ReadLine</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span>
修改complete方法如下：
<span style="color: #0600FF;">void</span> complete <span style="color: #000000;">&#40;</span>IAsyncResult iac<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
	<span style="color: #008080; font-style: italic;">//为了在complete方法中获取获取BeginInvoke最后一个参数，使用IAsyncResult参数的AsyncState属性.</span>
	Message  m <span style="color: #008000;">=</span> <span style="color: #000000;">&#40;</span>Message<span style="color: #000000;">&#41;</span>iac.<span style="color: #0000FF;">AsyncState</span><span style="color: #008000;">;</span>
	Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span>m.<span style="color: #0000FF;">msg</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
	Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;The stradd method has completed。&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span><span style="color: #008080; font-style: italic;">//告诉了主线程，次线程已经工作结束了。</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>Well done ! 这样我们就完成了对异步调用的讨论，下面我们总结一下，在异步调用中，我们需要深入理解委托的BeginInvoke方法，EndInvoke方法，IAsyncResult接口<br />
AsyncResult类，AsyncCallback委托。理解清楚这些方法，类，接口已经这几个之间的关系。就能够掌握异步调用的精髓了。</p>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2010/01/%e7%90%86%e8%a7%a3c%e4%b8%ad%e7%9a%84%e5%bc%82%e6%ad%a5%e6%96%b9%e6%b3%95/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[转]c# 多线程 编程</title>
		<link>http://amberlife.net/2010/01/%e8%bd%acc-%e5%a4%9a%e7%ba%bf%e7%a8%8b-%e7%bc%96%e7%a8%8b/</link>
		<comments>http://amberlife.net/2010/01/%e8%bd%acc-%e5%a4%9a%e7%ba%bf%e7%a8%8b-%e7%bc%96%e7%a8%8b/#comments</comments>
		<pubDate>Sun, 03 Jan 2010 15:23:27 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[多线程]]></category>

		<guid isPermaLink="false">http://amberlife.net/?p=173</guid>
		<description><![CDATA[一.多线程的概念
Windows是一个多任务的系统，如果你使用的是windows 2000及其以上版本，你可以通过任务管理器查看当前系统运行的程序和进程。什么是进程呢？当一个程序开始运行时，它就是一个进程，进程所指包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的，线程是程序中的一个执行流，每个线程都有自己的专有寄存器(栈指针、程序计数器等)，但代码区是共享的，即不同的线程可以执行同样的函数。多线程是指程序中包含多个执行流，即在一个程序中可以同时运行多个不同的线程来执行不同的任务，也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。浏览器就是一个很好的多线程的例子,在浏览器中你可以在下载JAVA小应用程序或图象的同时滚动页面,在访问新页面时,播放动画和声音,打印文件等。

多线程的好处在于可以提高CPU的利用率——任何一个程序员都不希望自己的程序很多时候没事可干，在多线程程序中，一个线程必须等待的时候，CPU可以运行其它的线程而不是等待，这样就大大提高了程序的效率。
然而我们也必须认识到线程本身可能影响系统性能的不利方面，以正确使用线程：
线程也是程序，所以线程需要占用内存，线程越多占用内存也越多
多线程需要协调和管理，所以需要CPU时间跟踪线程
线程之间对共享资源的访问会相互影响，必须解决竞用共享资源的问题
线程太多会导致控制太复杂，最终可能造成很多Bug
基于以上认识，我们可以一个比喻来加深理解。假设有一个公司，公司里有很多各司其职的职员，那么我们可以认为这个正常运作的公司就是一个进程，而公司里的职员就是线程。一个公司至少得有一个职员吧，同理，一个进程至少包含一个线程。在公司里，你可以一个职员干所有的事，但是效率很显然是高不起来的，一个人的公司也不可能做大；一个程序中也可以只用一个线程去做事，事实上，一些过时的语言如fortune,basic都是如此，但是象一个人的公司一样，效率很低，如果做大程序，效率更低——事实上现在几乎没有单线程的商业软件。公司的职员越多，老板就得发越多的薪水给他们，还得耗费大量精力去管理他们，协调他们之间的矛盾和利益；程序也是如此，线程越多耗费的资源也越多，需要CPU时间去跟踪线程，还得解决诸如死锁，同步等问题。总之，如果你不想你的公司被称为“皮包公司”，你就得多几个员工；如果你不想让你的程序显得稚气，就在你的程序里引入多线程吧！
本文将对C#编程中的多线程机制进行探讨，通过一些实例解决对线程的控制，多线程间通讯等问题。为了省去创建GUI那些繁琐的步骤，更清晰地逼近线程的本质，下面所有的程序都是控制台程序，程序最后的Console.ReadLine()是为了使程序中途停下来，以便看清楚执行过程中的输出。
好了，废话少说，让我们来体验一下多线程的C#吧！
二.操纵一个线程
任何程序在执行时，至少有一个主线程，下面这段小程序可以给读者一个直观的印象：
//SystemThread.cs
using System;
using System.Threading;
namespace ThreadTest
{
class RunIt
{
[STAThread]
static void Main(string[] args)
{
Thread.CurrentThread.Name=&#8221;System Thread&#8221;;//给当前线程起名为&#8221;System Thread&#8221;
Console.WriteLine(Thread.CurrentThread.Name+&#8221;&#8216;Status:&#8221;+Thread.CurrentThread.ThreadState);
Console.ReadLine();
}
}
}
编译执行后你看到了什么？是的，程序将产生如下输出：
System Thread&#8217;s Status:Running
在这里，我们通过Thread类的静态属性CurrentThread获取了当前执行的线程，对其Name属性赋值“System Thread”，最后还输出了它的当前状态（ThreadState）。所谓静态属性，就是这个类所有对象所公有的属性，不管你创建了多少个这个类的实例，但是类的静态属性在内存中只有一个。很容易理解CurrentThread为什么是静态的——虽然有多个线程同时存在，但是在某一个时刻，CPU只能执行其中一个。
就像上面程序所演示的，我们通过Thread类来创建和控制线程。注意到程序的头部，我们使用了如下命名空间：
using System;
using System.Threading;
在.net framework class library中，所有与多线程机制应用相关的类都是放在System.Threading命名空间中的。其中提供Thread类用于创建线程，ThreadPool类用于管理线程池等等，此外还提供解决了线程执行安排，死锁，线程间通讯等实际问题的机制。如果你想在你的应用程序中使用多线程，就必须包含这个类。Thread类有几个至关重要的方法，描述如下：
Start():启动线程
Sleep(int):静态方法，暂停当前线程指定的毫秒数
Abort():通常使用该方法来终止一个线程
Suspend()：该方法并不终止未完成的线程，它仅仅挂起线程，以后还可恢复。
Resume():恢复被Suspend()方法挂起的线程的执行
下面我们就动手来创建一个线程，使用Thread类创建线程时，只需提供线程入口即可。线程入口使程序知道该让这个线程干什么事，在C#中，线程入口是通过ThreadStart代理（delegate）来提供的，你可以把ThreadStart理解为一个函数指针，指向线程要执行的函数，当调用Thread.Start()方法后，线程就开始执行ThreadStart所代表或者说指向的函数。
打开你的VS.net，新建一个控制台应用程序（Console Application），下面这些代码将让你体味到完全控制一个线程的无穷乐趣！
//ThreadTest.cs
using System;
using System.Threading;
namespace ThreadTest
{
public class Alpha
{
public void Beta()
{
while (true)
{
Console.WriteLine(&#8221;Alpha.Beta is running in its own thread.&#8221;);
}
}
};
public class Simple
{
public static int Main()
{
Console.WriteLine(&#8221;Thread Start/Stop/Join Sample&#8221;);
Alpha oAlpha = new Alpha();
file://这里创建一个线程，使之执行Alpha类的Beta()方法
Thread oThread = new Thread(new ThreadStart(oAlpha.Beta));
oThread.Start();
while (!oThread.IsAlive);
Thread.Sleep(1);
oThread.Abort();
oThread.Join();
Console.WriteLine();
Console.WriteLine(&#8221;Alpha.Beta has finished&#8221;);
try
{
Console.WriteLine(&#8221;Try to restart [...]]]></description>
			<content:encoded><![CDATA[<p>一.多线程的概念</p>
<p>Windows是一个多任务的系统，如果你使用的是windows 2000及其以上版本，你可以通过任务管理器查看当前系统运行的程序和进程。什么是进程呢？当一个程序开始运行时，它就是一个进程，进程所指包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的，线程是程序中的一个执行流，每个线程都有自己的专有寄存器(栈指针、程序计数器等)，但代码区是共享的，即不同的线程可以执行同样的函数。多线程是指程序中包含多个执行流，即在一个程序中可以同时运行多个不同的线程来执行不同的任务，也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。浏览器就是一个很好的多线程的例子,在浏览器中你可以在下载JAVA小应用程序或图象的同时滚动页面,在访问新页面时,播放动画和声音,打印文件等。</p>
<p><span id="more-173"></span><br />
多线程的好处在于可以提高CPU的利用率——任何一个程序员都不希望自己的程序很多时候没事可干，在多线程程序中，一个线程必须等待的时候，CPU可以运行其它的线程而不是等待，这样就大大提高了程序的效率。</p>
<p>然而我们也必须认识到线程本身可能影响系统性能的不利方面，以正确使用线程：</p>
<p>线程也是程序，所以线程需要占用内存，线程越多占用内存也越多<br />
多线程需要协调和管理，所以需要CPU时间跟踪线程<br />
线程之间对共享资源的访问会相互影响，必须解决竞用共享资源的问题<br />
线程太多会导致控制太复杂，最终可能造成很多Bug</p>
<p>基于以上认识，我们可以一个比喻来加深理解。假设有一个公司，公司里有很多各司其职的职员，那么我们可以认为这个正常运作的公司就是一个进程，而公司里的职员就是线程。一个公司至少得有一个职员吧，同理，一个进程至少包含一个线程。在公司里，你可以一个职员干所有的事，但是效率很显然是高不起来的，一个人的公司也不可能做大；一个程序中也可以只用一个线程去做事，事实上，一些过时的语言如fortune,basic都是如此，但是象一个人的公司一样，效率很低，如果做大程序，效率更低——事实上现在几乎没有单线程的商业软件。公司的职员越多，老板就得发越多的薪水给他们，还得耗费大量精力去管理他们，协调他们之间的矛盾和利益；程序也是如此，线程越多耗费的资源也越多，需要CPU时间去跟踪线程，还得解决诸如死锁，同步等问题。总之，如果你不想你的公司被称为“皮包公司”，你就得多几个员工；如果你不想让你的程序显得稚气，就在你的程序里引入多线程吧！</p>
<p>本文将对C#编程中的多线程机制进行探讨，通过一些实例解决对线程的控制，多线程间通讯等问题。为了省去创建GUI那些繁琐的步骤，更清晰地逼近线程的本质，下面所有的程序都是控制台程序，程序最后的Console.ReadLine()是为了使程序中途停下来，以便看清楚执行过程中的输出。</p>
<p>好了，废话少说，让我们来体验一下多线程的C#吧！</p>
<p>二.操纵一个线程</p>
<p>任何程序在执行时，至少有一个主线程，下面这段小程序可以给读者一个直观的印象：</p>
<p>//SystemThread.cs<br />
using System;<br />
using System.Threading;</p>
<p>namespace ThreadTest<br />
{<br />
class RunIt<br />
{<br />
[STAThread]<br />
static void Main(string[] args)<br />
{<br />
Thread.CurrentThread.Name=&#8221;System Thread&#8221;;//给当前线程起名为&#8221;System Thread&#8221;<br />
Console.WriteLine(Thread.CurrentThread.Name+&#8221;&#8216;Status:&#8221;+Thread.CurrentThread.ThreadState);<br />
Console.ReadLine();<br />
}<br />
}<br />
}</p>
<p>编译执行后你看到了什么？是的，程序将产生如下输出：</p>
<p>System Thread&#8217;s Status:Running</p>
<p>在这里，我们通过Thread类的静态属性CurrentThread获取了当前执行的线程，对其Name属性赋值“System Thread”，最后还输出了它的当前状态（ThreadState）。所谓静态属性，就是这个类所有对象所公有的属性，不管你创建了多少个这个类的实例，但是类的静态属性在内存中只有一个。很容易理解CurrentThread为什么是静态的——虽然有多个线程同时存在，但是在某一个时刻，CPU只能执行其中一个。</p>
<p>就像上面程序所演示的，我们通过Thread类来创建和控制线程。注意到程序的头部，我们使用了如下命名空间：</p>
<p>using System;<br />
using System.Threading;</p>
<p>在.net framework class library中，所有与多线程机制应用相关的类都是放在System.Threading命名空间中的。其中提供Thread类用于创建线程，ThreadPool类用于管理线程池等等，此外还提供解决了线程执行安排，死锁，线程间通讯等实际问题的机制。如果你想在你的应用程序中使用多线程，就必须包含这个类。Thread类有几个至关重要的方法，描述如下：</p>
<p>Start():启动线程<br />
Sleep(int):静态方法，暂停当前线程指定的毫秒数<br />
Abort():通常使用该方法来终止一个线程<br />
Suspend()：该方法并不终止未完成的线程，它仅仅挂起线程，以后还可恢复。<br />
Resume():恢复被Suspend()方法挂起的线程的执行<br />
下面我们就动手来创建一个线程，使用Thread类创建线程时，只需提供线程入口即可。线程入口使程序知道该让这个线程干什么事，在C#中，线程入口是通过ThreadStart代理（delegate）来提供的，你可以把ThreadStart理解为一个函数指针，指向线程要执行的函数，当调用Thread.Start()方法后，线程就开始执行ThreadStart所代表或者说指向的函数。</p>
<p>打开你的VS.net，新建一个控制台应用程序（Console Application），下面这些代码将让你体味到完全控制一个线程的无穷乐趣！</p>
<p>//ThreadTest.cs</p>
<p>using System;<br />
using System.Threading;</p>
<p>namespace ThreadTest<br />
{<br />
public class Alpha<br />
{<br />
public void Beta()<br />
{<br />
while (true)<br />
{<br />
Console.WriteLine(&#8221;Alpha.Beta is running in its own thread.&#8221;);<br />
}<br />
}<br />
};</p>
<p>public class Simple<br />
{<br />
public static int Main()<br />
{<br />
Console.WriteLine(&#8221;Thread Start/Stop/Join Sample&#8221;);</p>
<p>Alpha oAlpha = new Alpha();<br />
file://这里创建一个线程，使之执行Alpha类的Beta()方法<br />
Thread oThread = new Thread(new ThreadStart(oAlpha.Beta));<br />
oThread.Start();<br />
while (!oThread.IsAlive);<br />
Thread.Sleep(1);<br />
oThread.Abort();<br />
oThread.Join();<br />
Console.WriteLine();<br />
Console.WriteLine(&#8221;Alpha.Beta has finished&#8221;);<br />
try<br />
{<br />
Console.WriteLine(&#8221;Try to restart the Alpha.Beta thread&#8221;);<br />
oThread.Start();<br />
}<br />
catch (ThreadStateException)<br />
{<br />
Console.Write(&#8221;ThreadStateException trying to restart Alpha.Beta. &#8220;);<br />
Console.WriteLine(&#8221;Expected since aborted threads cannot be restarted.&#8221;);<br />
Console.ReadLine();<br />
}<br />
return 0;<br />
}<br />
}<br />
}</p>
<p>这段程序包含两个类Alpha和Simple，在创建线程oThread时我们用指向Alpha.Beta()方法的初始化了ThreadStart代理（delegate）对象，当我们创建的线程oThread调用oThread.Start()方法启动时，实际上程序运行的是Alpha.Beta()方法：</p>
<p>Alpha oAlpha = new Alpha();<br />
Thread oThread = new Thread(new ThreadStart(oAlpha.Beta));<br />
oThread.Start();</p>
<p>然后在Main()函数的while循环中，我们使用静态方法Thread.Sleep()让主线程停了1ms，这段时间CPU转向执行线程oThread。然后我们试图用Thread.Abort()方法终止线程oThread，注意后面的oThread.Join()，Thread.Join()方法使主线程等待，直到oThread线程结束。你可以给Thread.Join()方法指定一个int型的参数作为等待的最长时间。之后，我们试图用Thread.Start()方法重新启动线程oThread，但是显然Abort()方法带来的后果是不可恢复的终止线程，所以最后程序会抛出ThreadStateException异常。</p>
<p>程序最后得到的结果将如下图：<br />
在这里我们要注意的是其它线程都是依附于Main()函数所在的线程的，Main()函数是C#程序的入口，起始线程可以称之为主线程，如果所有的前台线程都停止了，那么主线程可以终止，而所有的后台线程都将无条件终止。而所有的线程虽然在微观上是串行执行的，但是在宏观上你完全可以认为它们在并行执行。</p>
<p>读者一定注意到了Thread.ThreadState这个属性，这个属性代表了线程运行时状态，在不同的情况下有不同的值，于是我们有时候可以通过对该值的判断来设计程序流程。ThreadState在各种情况下的可能取值如下：</p>
<p>Aborted：线程已停止<br />
AbortRequested：线程的Thread.Abort()方法已被调用，但是线程还未停止<br />
Background：线程在后台执行，与属性Thread.IsBackground有关<br />
Running：线程正在正常运行<br />
Stopped：线程已经被停止<br />
StopRequested：线程正在被要求停止<br />
Suspended：线程已经被挂起（此状态下，可以通过调用Resume()方法重新运行）<br />
SuspendRequested：线程正在要求被挂起，但是未来得及响应<br />
Unstarted：未调用Thread.Start()开始线程的运行<br />
WaitSleepJoin：线程因为调用了Wait(),Sleep()或Join()等方法处于封锁状态<br />
上面提到了Background状态表示该线程在后台运行，那么后台运行的线程有什么特别的地方呢？其实后台线程跟前台线程只有一个区别，那就是后台线程不妨碍程序的终止。一旦一个进程所有的前台线程都终止后，CLR（通用语言运行环境）将通过调用任意一个存活中的后台进程的Abort()方法来彻底终止进程。</p>
<p>当线程之间争夺CPU时间时，CPU按照是线程的优先级给予服务的。在C#应用程序中，用户可以设定5个不同的优先级，由高到低分别是Highest，AboveNormal，Normal，BelowNormal，Lowest，在创建线程时如果不指定优先级，那么系统默认为ThreadPriority.Normal。给一个线程指定优先级<br />
，我们可以使用如下代码：</p>
<p>//设定优先级为最低<br />
myThread.Priority=ThreadPriority.Lowest;</p>
<p>通过设定线程的优先级，我们可以安排一些相对重要的线程优先执行，例如对用户的响应等等。</p>
<p>现在我们对怎样创建和控制一个线程已经有了一个初步的了解，下面我们将深入研究线程实现中比较典型的的问题，并且探讨其解决方法。</p>
<p>三.线程的同步和通讯——生产者和消费者</p>
<p>假设这样一种情况，两个线程同时维护一个队列，如果一个线程对队列中添加元素，而另外一个线程从队列中取用元素，那么我们称添加元素的线程为生产者，称取用元素的线程为消费者。生产者与消费者问题看起来很简单，但是却是多线程应用中一个必须解决的问题，它涉及到线程之间的同步和通讯问题。</p>
<p>前面说过，每个线程都有自己的资源，但是代码区是共享的，即每个线程都可以执行相同的函数。但是多线程环境下，可能带来的问题就是几个线程同时执行一个函数，导致数据的混乱，产生不可预料的结果，因此我们必须避免这种情况的发生。C#提供了一个关键字lock，它可以把一段代码定义为互斥段（critical section），互斥段在一个时刻内只允许一个线程进入执行，而其他线程必须等待。在C#中，关键字lock定义如下：</p>
<p>lock(expression) statement_block<br />
expression代表你希望跟踪的对象，通常是对象引用。一般地，如果你想保护一个类的实例，你可以使用this；如果你希望保护一个静态变量（如互斥代码段在一个静态方法内部），一般使用类名就可以了。而statement_block就是互斥段的代码，这段代码在一个时刻内只可能被一个线程执行。</p>
<p>下面是一个使用lock关键字的典型例子，我将在注释里向大家说明lock关键字的用法和用途：</p>
<p>//lock.cs<br />
using System;<br />
using System.Threading;</p>
<p>internal class Account<br />
{<br />
int balance;<br />
Random r = new Random();<br />
internal Account(int initial)<br />
{<br />
balance = initial;<br />
}</p>
<p>internal int Withdraw(int amount)<br />
{<br />
if (balance &lt; 0)<br />
{<br />
file://如果balance小于0则抛出异常<br />
throw new Exception(&#8221;Negative Balance&#8221;);<br />
}<br />
//下面的代码保证在当前线程修改balance的值完成之前<br />
//不会有其他线程也执行这段代码来修改balance的值<br />
//因此，balance的值是不可能小于0的<br />
lock (this)<br />
{<br />
Console.WriteLine(&#8221;Current Thread:&#8221;+Thread.CurrentThread.Name);<br />
file://如果没有lock关键字的保护，那么可能在执行完if的条件判断之后<br />
file://另外一个线程却执行了balance=balance-amount修改了balance的值<br />
file://而这个修改对这个线程是不可见的，所以可能导致这时if的条件已经不成立了<br />
file://但是，这个线程却继续执行balance=balance-amount，所以导致balance可能小于0<br />
if (balance &gt;= amount)<br />
{<br />
Thread.Sleep(5);<br />
balance = balance &#8211; amount;<br />
return amount;<br />
}<br />
else<br />
{<br />
return 0; // transaction rejected<br />
}<br />
}<br />
}<br />
internal void DoTransactions()<br />
{<br />
for (int i = 0; i &lt; 100; i++)<br />
Withdraw(r.Next(-50, 100));<br />
}<br />
}</p>
<p>internal class Test<br />
{<br />
static internal Thread[] threads = new Thread[10];<br />
public static void Main()<br />
{<br />
Account acc = new Account (0);<br />
for (int i = 0; i &lt; 10; i++)<br />
{<br />
Thread t = new Thread(new ThreadStart(acc.DoTransactions));<br />
threads[i] = t;<br />
}<br />
for (int i = 0; i &lt; 10; i++)<br />
threads[i].Name=i.ToString();<br />
for (int i = 0; i &lt; 10; i++)<br />
threads[i].Start();<br />
Console.ReadLine();<br />
}<br />
}</p>
<p>而多线程公用一个对象时，也会出现和公用代码类似的问题，这种问题就不应该使用lock关键字了，这里需要用到System.Threading中的一个类Monitor，我们可以称之为监视器，Monitor提供了使线程共享资源的方案。</p>
<p>Monitor类可以锁定一个对象，一个线程只有得到这把锁才可以对该对象进行操作。对象锁机制保证了在可能引起混乱的情况下一个时刻只有一个线程可以访问这个对象。Monitor必须和一个具体的对象相关联，但是由于它是一个静态的类，所以不能使用它来定义对象，而且它的所有方法都是静态的，不能使用对象来引用。下面代码说明了使用Monitor锁定一个对象的情形：</p>
<p>&#8230;&#8230;<br />
Queue oQueue=new Queue();<br />
&#8230;&#8230;<br />
Monitor.Enter(oQueue);<br />
&#8230;&#8230;//现在oQueue对象只能被当前线程操纵了<br />
Monitor.Exit(oQueue);//释放锁</p>
<p>如上所示，当一个线程调用Monitor.Enter()方法锁定一个对象时，这个对象就归它所有了，其它线程想要访问这个对象，只有等待它使用Monitor.Exit()方法释放锁。为了保证线程最终都能释放锁，你可以把Monitor.Exit()方法写在try-catch-finally结构中的finally代码块里。对于任何一个被Monitor锁定的对象，内存中都保存着与它相关的一些信息，其一是现在持有锁的线程的引用，其二是一个预备队列，队列中保存了已经准备好获取锁的线程，其三是一个等待队列，队列中保存着当前正在等待这个对象状态改变的队列的引用。当拥有对象锁的线程准备释放锁时，它使用Monitor.Pulse()方法通知等待队列中的第一个线程，于是该线程被转移到预备队列中，当对象锁被释放时，在预备队列中的线程可以立即获得对象锁。</p>
<p>下面是一个展示如何使用lock关键字和Monitor类来实现线程的同步和通讯的例子，也是一个典型的生产者与消费者问题。这个例程中，生产者线程和消费者线程是交替进行的，生产者写入一个数，消费者立即读取并且显示，我将在注释中介绍该程序的精要所在。用到的系统命名空间如下：</p>
<p>using System;<br />
using System.Threading;<br />
首先，我们定义一个被操作的对象的类Cell，在这个类里，有两个方法：ReadFromCell()和WriteToCell。消费者线程将调用ReadFromCell()读取cellContents的内容并且显示出来，生产者进程将调用WriteToCell()方法向cellContents写入数据。</p>
<p>public class Cell<br />
{<br />
int cellContents; // Cell对象里边的内容<br />
bool readerFlag = false; // 状态标志，为true时可以读取，为false则正在写入<br />
public int ReadFromCell( )<br />
{<br />
lock(this) // Lock关键字保证了什么，请大家看前面对lock的介绍<br />
{<br />
if (!readerFlag)//如果现在不可读取<br />
{<br />
try<br />
{<br />
file://等待WriteToCell方法中调用Monitor.Pulse()方法<br />
Monitor.Wait(this);<br />
}<br />
catch (SynchronizationLockException e)<br />
{<br />
Console.WriteLine(e);<br />
}<br />
catch (ThreadInterruptedException e)<br />
{<br />
Console.WriteLine(e);<br />
}<br />
}<br />
Console.WriteLine(&#8221;Consume: {0}&#8221;,cellContents);<br />
readerFlag = false; file://重置readerFlag标志，表示消费行为已经完成<br />
Monitor.Pulse(this); file://通知WriteToCell()方法（该方法在另外一个线程中执行，等待中）<br />
}<br />
return cellContents;<br />
}</p>
<p>public void WriteToCell(int n)<br />
{<br />
lock(this)<br />
{<br />
if (readerFlag)<br />
{<br />
try<br />
{<br />
Monitor.Wait(this);<br />
}<br />
catch (SynchronizationLockException e)<br />
{<br />
file://当同步方法（指Monitor类除Enter之外的方法）在非同步的代码区被调用<br />
Console.WriteLine(e);<br />
}<br />
catch (ThreadInterruptedException e)<br />
{<br />
file://当线程在等待状态的时候中止<br />
Console.WriteLine(e);<br />
}<br />
}<br />
cellContents = n;<br />
Console.WriteLine(&#8221;Produce: {0}&#8221;,cellContents);<br />
readerFlag = true;<br />
Monitor.Pulse(this); file://通知另外一个线程中正在等待的ReadFromCell()方法<br />
}<br />
}<br />
}</p>
<p>下面定义生产者CellProd和消费者类CellCons，它们都只有一个方法ThreadRun()，以便在Main()函数中提供给线程的ThreadStart代理对象，作为线程的入口。</p>
<p>public class CellProd<br />
{<br />
Cell cell; // 被操作的Cell对象<br />
int quantity = 1; // 生产者生产次数，初始化为1</p>
<p>public CellProd(Cell box, int request)<br />
{<br />
//构造函数<br />
cell = box;<br />
quantity = request;<br />
}<br />
public void ThreadRun( )<br />
{<br />
for(int looper=1; looper&lt;=quantity; looper++)<br />
cell.WriteToCell(looper); file://生产者向操作对象写入信息<br />
}<br />
}</p>
<p>public class CellCons<br />
{<br />
Cell cell;<br />
int quantity = 1;</p>
<p>public CellCons(Cell box, int request)<br />
{<br />
cell = box;<br />
quantity = request;<br />
}<br />
public void ThreadRun( )<br />
{<br />
int valReturned;<br />
for(int looper=1; looper&lt;=quantity; looper++)<br />
valReturned=cell.ReadFromCell( );//消费者从操作对象中读取信息<br />
}<br />
}<br />
然后在下面这个类MonitorSample的Main()函数中我们要做的就是创建两个线程分别作为生产者和消费者，使用CellProd.ThreadRun()方法和CellCons.ThreadRun()方法对同一个Cell对象进行操作。</p>
<p>public class MonitorSample<br />
{<br />
public static void Main(String[] args)<br />
{<br />
int result = 0; file://一个标志位，如果是0表示程序没有出错，如果是1表明有错误发生<br />
Cell cell = new Cell( );</p>
<p>//下面使用cell初始化CellProd和CellCons两个类，生产和消费次数均为20次<br />
CellProd prod = new CellProd(cell, 20);<br />
CellCons cons = new CellCons(cell, 20);</p>
<p>Thread producer = new Thread(new ThreadStart(prod.ThreadRun));<br />
Thread consumer = new Thread(new ThreadStart(cons.ThreadRun));<br />
//生产者线程和消费者线程都已经被创建，但是没有开始执行</p>
<p>try<br />
{<br />
producer.Start( );<br />
consumer.Start( );</p>
<p>producer.Join( );<br />
consumer.Join( );<br />
Console.ReadLine();<br />
}<br />
catch (ThreadStateException e)<br />
{<br />
file://当线程因为所处状态的原因而不能执行被请求的操作<br />
Console.WriteLine(e);<br />
result = 1;<br />
}<br />
catch (ThreadInterruptedException e)<br />
{<br />
file://当线程在等待状态的时候中止<br />
Console.WriteLine(e);<br />
result = 1;<br />
}<br />
//尽管Main()函数没有返回值，但下面这条语句可以向父进程返回执行结果<br />
Environment.ExitCode = result;<br />
}<br />
}<br />
大家可以看到，在上面的例程中，同步是通过等待Monitor.Pulse()来完成的。首先生产者生产了一个值，而同一时刻消费者处于等待状态，直到收到生产者的“脉冲(Pulse)”通知它生产已经完成，此后消费者进入消费状态，而生产者开始等待消费者完成操作后将调用Monitor.Pulese()发出的“脉冲”。它的执行结果很简单：</p>
<p>Produce: 1<br />
Consume: 1<br />
Produce: 2<br />
Consume: 2<br />
Produce: 3<br />
Consume: 3<br />
&#8230;<br />
&#8230;<br />
Produce: 20<br />
Consume: 20</p>
<p>事实上，这个简单的例子已经帮助我们解决了多线程应用程序中可能出现的大问题，只要领悟了解决线程间冲突的基本方法，很容易把它应用到比较复杂的程序中去。</p>
<p>四、线程池和定时器——多线程的自动管理<br />
在多线程的程序中，经常会出现两种情况。一种情况下，应用程序中的线程把大部分的时间花费在等待状态，等待某个事件发生，然后才能给予响应；而另外一种情况则是线程平常都处于休眠状态，只是周期性地被唤醒。在.net framework里边，我们使用ThreadPool来对付第一种情况，使用Timer来对付第二种情况。</p>
<p>ThreadPool类提供一个由系统维护的线程池——可以看作一个线程的容器，该容器需要Windows 2000以上版本的系统支持，因为其中某些方法调用了只有高版本的Windows才有的API函数。你可以使用ThreadPool.QueueUserWorkItem()方法将线程安放在线程池里，该方法的原型如下：</p>
<p>//将一个线程放进线程池，该线程的Start()方法将调用WaitCallback代理对象代表的函数<br />
public static bool QueueUserWorkItem(WaitCallback);<br />
//重载的方法如下，参数object将传递给WaitCallback所代表的方法<br />
public static bool QueueUserWorkItem(WaitCallback, object);</p>
<p>要注意的是，ThreadPool类也是一个静态类，你不能也不必要生成它的对象，而且一旦使用该方法在线程池中添加了一个项目，那么该项目将是没有办法取消的。在这里你无需自己建立线程，只需把你要做的工作写成函数，然后作为参数传递给ThreadPool.QueueUserWorkItem()方法就行了，传递的方法就是依靠WaitCallback代理对象，而线程的建立、管理、运行等等工作都是由系统自动完成的，你无须考虑那些复杂的细节问题，线程池的优点也就在这里体现出来了，就好像你是公司老板——只需要安排工作，而不必亲自动手。<br />
下面的例程演示了ThreadPool的用法。首先程序创建了一个ManualResetEvent对象，该对象就像一个信号灯，可以利用它的信号来通知其它线程，本例中当线程池中所有线程工作都完成以后，ManualResetEvent的对象将被设置为有信号，从而通知主线程继续运行。它有几个重要的方法：Reset()，Set()，WaitOne()。初始化该对象时，用户可以指定其默认的状态（有信号/无信号），在初始化以后，该对象将保持原来的状态不变直到它的Reset()或者Set()方法被调用，Reset()方法将其设置为无信号状态，Set()方法将其设置为有信号状态。WaitOne()方法使当前线程挂起直到ManualResetEvent对象处于有信号状态，此时该线程将被激活。然后，程序将向线程池中添加工作项，这些以函数形式提供的工作项被系统用来初始化自动建立的线程。当所有的线程都运行完了以后，ManualResetEvent.Set()方法被调用，因为调用了ManualResetEvent.WaitOne()方法而处在等待状态的主线程将接收到这个信号，于是它接着往下执行，完成后边的工作。</p>
<p>using System;<br />
using System.Collections;<br />
using System.Threading;</p>
<p>//这是用来保存信息的数据结构，将作为参数被传递<br />
public class SomeState<br />
{<br />
public int Cookie;<br />
public SomeState(int iCookie)<br />
{<br />
Cookie = iCookie;<br />
}<br />
}</p>
<p>public class Alpha<br />
{<br />
public Hashtable HashCount;<br />
public ManualResetEvent eventX;<br />
public static int iCount = 0;<br />
public static int iMaxCount = 0;<br />
public Alpha(int MaxCount)<br />
{<br />
HashCount = new Hashtable(MaxCount);<br />
iMaxCount = MaxCount;<br />
}</p>
<p>file://线程池里的线程将调用Beta()方法<br />
public void Beta(Object state)<br />
{<br />
//输出当前线程的hash编码值和Cookie的值<br />
Console.WriteLine(&#8221; {0} {1} :&#8221;, Thread.CurrentThread.GetHashCode(),<br />
((SomeState)state).Cookie);<br />
Console.WriteLine(&#8221;HashCount.Count=={0}, Thread.CurrentThread.GetHashCode()=={1}&#8221;, HashCount.Count, Thread.CurrentThread.GetHashCode());<br />
lock (HashCount)<br />
{<br />
file://如果当前的Hash表中没有当前线程的Hash值，则添加之<br />
if (!HashCount.ContainsKey(Thread.CurrentThread.GetHashCode()))<br />
HashCount.Add (Thread.CurrentThread.GetHashCode(), 0);<br />
HashCount[Thread.CurrentThread.GetHashCode()] =<br />
((int)HashCount[Thread.CurrentThread.GetHashCode()])+1;<br />
}</p>
<p>int iX = 2000;<br />
Thread.Sleep(iX);<br />
//Interlocked.Increment()操作是一个原子操作，具体请看下面说明<br />
Interlocked.Increment(ref iCount);<br />
if (iCount == iMaxCount)<br />
{<br />
Console.WriteLine();<br />
Console.WriteLine(&#8221;Setting eventX &#8220;);<br />
eventX.Set();<br />
}<br />
}<br />
}</p>
<p>public class SimplePool<br />
{<br />
public static int Main(string[] args)<br />
{<br />
Console.WriteLine(&#8221;Thread Pool Sample:&#8221;);<br />
bool W2K = false;<br />
int MaxCount = 10;//允许线程池中运行最多10个线程<br />
//新建ManualResetEvent对象并且初始化为无信号状态<br />
ManualResetEvent eventX = new ManualResetEvent(false);<br />
Console.WriteLine(&#8221;Queuing {0} items to Thread Pool&#8221;, MaxCount);<br />
Alpha oAlpha = new Alpha(MaxCount); file://创建工作项<br />
//注意初始化oAlpha对象的eventX属性<br />
oAlpha.eventX = eventX;<br />
Console.WriteLine(&#8221;Queue to Thread Pool 0&#8243;);<br />
try<br />
{<br />
file://将工作项装入线程池<br />
file://这里要用到Windows 2000以上版本才有的API，所以可能出现NotSupportException异常<br />
ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta),<br />
new SomeState(0));<br />
W2K = true;<br />
}<br />
catch (NotSupportedException)<br />
{<br />
Console.WriteLine(&#8221;These API&#8217;s may fail when called on a non-Windows 2000 system.&#8221;);<br />
W2K = false;<br />
}<br />
if (W2K)//如果当前系统支持ThreadPool的方法.<br />
{<br />
for (int iItem=1;iItem &lt; MaxCount;iItem++)<br />
{<br />
//插入队列元素<br />
Console.WriteLine(&#8221;Queue to Thread Pool {0}&#8221;, iItem);<br />
ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta),new SomeState(iItem));<br />
}<br />
Console.WriteLine(&#8221;Waiting for Thread Pool to drain&#8221;);<br />
file://等待事件的完成，即线程调用ManualResetEvent.Set()方法<br />
eventX.WaitOne(Timeout.Infinite,true);<br />
file://WaitOne()方法使调用它的线程等待直到eventX.Set()方法被调用<br />
Console.WriteLine(&#8221;Thread Pool has been drained (Event fired)&#8221;);<br />
Console.WriteLine();<br />
Console.WriteLine(&#8221;Load across threads&#8221;);<br />
foreach(object o in oAlpha.HashCount.Keys)<br />
Console.WriteLine(&#8221;{0} {1}&#8221;, o, oAlpha.HashCount[o]);<br />
}<br />
Console.ReadLine();<br />
return 0;</p>
<p>}<br />
}</p>
<p>程序中有些小地方应该引起我们的注意。SomeState类是一个保存信息的数据结构，在上面的程序中，它作为参数被传递给每一个线程，你很容易就能理解这个，因为你需要把一些有用的信息封装起来提供给线程，而这种方式是非常有效的。程序出现的InterLocked类也是专为多线程程序而存在的，它提供了一些有用的原子操作，所谓原子操作就是在多线程程序中，如果这个线程调用这个操作修改一个变量，那么其他线程就不能修改这个变量了，这跟lock关键字在本质上是一样的。</p>
<p>我们应该彻底地分析上面的程序，把握住线程池的本质，理解它存在的意义是什么，这样我们才能得心应手地使用它。下面是该程序的输出结果：<br />
Thread Pool Sample:<br />
Queuing 10 items to Thread Pool<br />
Queue to Thread Pool 0<br />
Queue to Thread Pool 1<br />
&#8230;<br />
&#8230;<br />
Queue to Thread Pool 9<br />
Waiting for Thread Pool to drain<br />
98 0 :<br />
HashCount.Count==0, Thread.CurrentThread.GetHashCode()==98<br />
100 1 :<br />
HashCount.Count==1, Thread.CurrentThread.GetHashCode()==100<br />
98 2 :<br />
&#8230;<br />
&#8230;<br />
Setting eventX<br />
Thread Pool has been drained (Event fired)<br />
Load across threads<br />
101 2<br />
100 3<br />
98 4<br />
102 1</p>
<p>与ThreadPool类不同，Timer类的作用是设置一个定时器，定时执行用户指定的函数，而这个函数的传递是靠另外一个代理对象TimerCallback，它必须在创建Timer对象时就指定，并且不能更改。定时器启动后，系统将自动建立一个新的线程，并且在这个线程里执行用户指定的函数。下面的语句初始化了一个Timer对象：<br />
Timer timer = new Timer(timerDelegate, s,1000, 1000);</p>
<p>第一个参数指定了TimerCallback代理对象；第二个参数的意义跟上面提到的WaitCallback代理对象的一样，作为一个传递数据的对象传递给要调用的方法；第三个参数是延迟时间——计时开始的时刻距现在的时间，单位是毫秒；第四个参数是定时器的时间间隔——计时开始以后，每隔这么长的一段时间，TimerCallback所代表的方法将被调用一次，单位也是毫秒。这句话的意思就是将定时器的延迟时间和时间间隔都设为1秒钟。</p>
<p>定时器的设置是可以改变的，只要调用Timer.Change()方法，这是一个参数类型重载的方法，一般使用的原型如下：<br />
 public bool Change(long, long);</p>
<p>下面这段代码将前边设置的定时器修改了一下：<br />
 timer.Change(10000,2000);</p>
<p>很显然，定时器timer的时间间隔被重新设置为2秒，停止计时10秒后生效。</p>
<p>下面这段程序演示了Timer类的用法。</p>
<p>using System;<br />
using System.Threading;<br />
class TimerExampleState<br />
{<br />
public int counter = 0;<br />
public Timer tmr;<br />
}</p>
<p>class App<br />
{<br />
public static void Main()<br />
{<br />
TimerExampleState s = new TimerExampleState();</p>
<p>//创建代理对象TimerCallback，该代理将被定时调用<br />
TimerCallback timerDelegate = new TimerCallback(CheckStatus);</p>
<p>//创建一个时间间隔为1s的定时器<br />
Timer timer = new Timer(timerDelegate, s,1000, 1000);<br />
s.tmr = timer;</p>
<p>//主线程停下来等待Timer对象的终止<br />
while(s.tmr != null)<br />
Thread.Sleep(0);<br />
Console.WriteLine(&#8221;Timer example done.&#8221;);<br />
Console.ReadLine();<br />
}<br />
file://下面是被定时调用的方法</p>
<p>static void CheckStatus(Object state)<br />
{<br />
TimerExampleState s =(TimerExampleState)state;<br />
s.counter++;<br />
Console.WriteLine(&#8221;{0} Checking Status {1}.&#8221;,DateTime.Now.TimeOfDay, s.counter);<br />
if(s.counter == 5)<br />
{<br />
file://使用Change方法改变了时间间隔<br />
(s.tmr).Change(10000,2000);<br />
Console.WriteLine(&#8221;changed&#8230;&#8221;);<br />
}<br />
if(s.counter == 10)<br />
{<br />
Console.WriteLine(&#8221;disposing of timer&#8230;&#8221;);<br />
s.tmr.Dispose();<br />
s.tmr = null;<br />
}<br />
}<br />
}</p>
<p>程序首先创建了一个定时器，它将在创建1秒之后开始每隔1秒调用一次CheckStatus()方法，当调用5次以后，在CheckStatus()方法中修改了时间间隔为2秒，并且指定在10秒后重新开始。当计数达到10次，调用Timer.Dispose()方法删除了timer对象，主线程于是跳出循环，终止程序。程序执行的结果如下：</p>
<p>上面就是对ThreadPool和Timer两个类的简单介绍，充分利用系统提供的功能，可以为我们省去很多时间和精力——特别是对很容易出错的多线程程序。同时我们也可以看到.net Framework强大的内置对象，这些将对我们的编程带来莫大的方便。<br />
五、互斥对象——更加灵活的同步方式</p>
<p>有时候你会觉得上面介绍的方法好像不够用，对，我们解决了代码和资源的同步问题，解决了多线程自动化管理和定时触发的问题，但是如何控制多个线程相互之间的联系呢？例如我要到餐厅吃饭，在吃饭之前我先得等待厨师把饭菜做好，之后我开始吃饭，吃完我还得付款，付款方式可以是现金，也可以是信用卡，付款之后我才能离开。分析一下这个过程，我吃饭可以看作是主线程，厨师做饭又是一个线程，服务员用信用卡收款和收现金可以看作另外两个线程，大家可以很清楚地看到其中的关系——我吃饭必须等待厨师做饭，然后等待两个收款线程之中任意一个的完成，然后我吃饭这个线程可以执行离开这个步骤，于是我吃饭才算结束了。事实上，现实中有着比这更复杂的联系，我们怎样才能很好地控制它们而不产生冲突和重复呢？</p>
<p>这种情况下，我们需要用到互斥对象，即System.Threading命名空间中的Mutex类。大家一定坐过出租车吧，事实上我们可以把Mutex看作一个出租车，那么乘客就是线程了，乘客首先得等车，然后上车，最后下车，当一个乘客在车上时，其他乘客就只有等他下车以后才可以上车。而线程与Mutex对象的关系也正是如此，线程使用Mutex.WaitOne()方法等待Mutex对象被释放，如果它等待的Mutex对象被释放了，它就自动拥有这个对象，直到它调用Mutex.ReleaseMutex()方法释放这个对象，而在此期间，其他想要获取这个Mutex对象的线程都只有等待。</p>
<p>下面这个例子使用了Mutex对象来同步四个线程，主线程等待四个线程的结束，而这四个线程的运行又是与两个Mutex对象相关联的。其中还用到AutoResetEvent类的对象，如同上面提到的ManualResetEvent对象一样，大家可以把它简单地理解为一个信号灯，使用AutoResetEvent.Set()方法可以设置它为有信号状态，而使用AutoResetEvent.Reset()方法把它设置为无信号状态。这里用它的有信号状态来表示一个线程的结束。</p>
<p>// Mutex.cs<br />
using System;<br />
using System.Threading;</p>
<p>public class MutexSample<br />
{<br />
static Mutex gM1;<br />
static Mutex gM2;<br />
const int ITERS = 100;<br />
static AutoResetEvent Event1 = new AutoResetEvent(false);<br />
static AutoResetEvent Event2 = new AutoResetEvent(false);<br />
static AutoResetEvent Event3 = new AutoResetEvent(false);<br />
static AutoResetEvent Event4 = new AutoResetEvent(false);</p>
<p>public static void Main(String[] args)<br />
{<br />
Console.WriteLine(&#8221;Mutex Sample &#8230;&#8221;);<br />
//创建一个Mutex对象，并且命名为MyMutex<br />
gM1 = new Mutex(true,&#8221;MyMutex&#8221;);<br />
//创建一个未命名的Mutex 对象.<br />
gM2 = new Mutex(true);<br />
Console.WriteLine(&#8221; &#8211; Main Owns gM1 and gM2&#8243;);</p>
<p>AutoResetEvent[] evs = new AutoResetEvent[4];<br />
evs[0] = Event1; file://为后面的线程t1,t2,t3,t4定义AutoResetEvent对象<br />
evs[1] = Event2;<br />
evs[2] = Event3;<br />
evs[3] = Event4;</p>
<p>MutexSample tm = new MutexSample( );<br />
Thread t1 = new Thread(new ThreadStart(tm.t1Start));<br />
Thread t2 = new Thread(new ThreadStart(tm.t2Start));<br />
Thread t3 = new Thread(new ThreadStart(tm.t3Start));<br />
Thread t4 = new Thread(new ThreadStart(tm.t4Start));<br />
t1.Start( );// 使用Mutex.WaitAll()方法等待一个Mutex数组中的对象全部被释放<br />
t2.Start( );// 使用Mutex.WaitOne()方法等待gM1的释放<br />
t3.Start( );// 使用Mutex.WaitAny()方法等待一个Mutex数组中任意一个对象被释放<br />
t4.Start( );// 使用Mutex.WaitOne()方法等待gM2的释放</p>
<p>Thread.Sleep(2000);<br />
Console.WriteLine(&#8221; &#8211; Main releases gM1&#8243;);<br />
gM1.ReleaseMutex( ); file://线程t2,t3结束条件满足</p>
<p>Thread.Sleep(1000);<br />
Console.WriteLine(&#8221; &#8211; Main releases gM2&#8243;);<br />
gM2.ReleaseMutex( ); file://线程t1,t4结束条件满足</p>
<p>//等待所有四个线程结束<br />
WaitHandle.WaitAll(evs);<br />
Console.WriteLine(&#8221;&#8230; Mutex Sample&#8221;);<br />
Console.ReadLine();<br />
}</p>
<p>public void t1Start( )<br />
{<br />
Console.WriteLine(&#8221;t1Start started, Mutex.WaitAll(Mutex[])&#8221;);<br />
Mutex[] gMs = new Mutex[2];<br />
gMs[0] = gM1;//创建一个Mutex数组作为Mutex.WaitAll()方法的参数<br />
gMs[1] = gM2;<br />
Mutex.WaitAll(gMs);//等待gM1和gM2都被释放<br />
Thread.Sleep(2000);<br />
Console.WriteLine(&#8221;t1Start finished, Mutex.WaitAll(Mutex[]) satisfied&#8221;);<br />
Event1.Set( ); file://线程结束，将Event1设置为有信号状态<br />
}</p>
<p>public void t2Start( )<br />
{<br />
Console.WriteLine(&#8221;t2Start started, gM1.WaitOne( )&#8221;);<br />
gM1.WaitOne( );//等待gM1的释放<br />
Console.WriteLine(&#8221;t2Start finished, gM1.WaitOne( ) satisfied&#8221;);<br />
Event2.Set( );//线程结束，将Event2设置为有信号状态<br />
}</p>
<p>public void t3Start( )<br />
{<br />
Console.WriteLine(&#8221;t3Start started, Mutex.WaitAny(Mutex[])&#8221;);<br />
Mutex[] gMs = new Mutex[2];<br />
gMs[0] = gM1;//创建一个Mutex数组作为Mutex.WaitAny()方法的参数<br />
gMs[1] = gM2;<br />
Mutex.WaitAny(gMs);//等待数组中任意一个Mutex对象被释放<br />
Console.WriteLine(&#8221;t3Start finished, Mutex.WaitAny(Mutex[])&#8221;);<br />
Event3.Set( );//线程结束，将Event3设置为有信号状态<br />
}</p>
<p>public void t4Start( )<br />
{<br />
Console.WriteLine(&#8221;t4Start started, gM2.WaitOne( )&#8221;);<br />
gM2.WaitOne( );//等待gM2被释放<br />
Console.WriteLine(&#8221;t4Start finished, gM2.WaitOne( )&#8221;);<br />
Event4.Set( );//线程结束，将Event4设置为有信号状态<br />
}<br />
}</p>
<p>下面是该程序的执行结果：</p>
<p>从执行结果可以很清楚地看到，线程t2,t3的运行是以gM1的释放为条件的，而t4在gM2释放后开始执行，t1则在gM1和gM2都被释放了之后才执行。Main()函数最后，使用WaitHandle等待所有的AutoResetEvent对象的信号，这些对象的信号代表相应线程的结束。</p>
<p>六、小结</p>
<p>多线程程序设计是一个庞大的主题，而本文试图在.net Framework环境下，使用最新的C#语言来描述多线程程序的概貌。希望本文能有助于大家理解线程这种概念，理解多线程的用途，理解它的C#实现方法，理解线程将为我们带来的好处和麻烦。C#是一种新的语言，因此它的线程机制也有许多独特的地方，希望大家能通过本文清楚地看到这些，从而可以对线程进行更深入的理解和探索。</p>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2010/01/%e8%bd%acc-%e5%a4%9a%e7%ba%bf%e7%a8%8b-%e7%bc%96%e7%a8%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>进程、线程与应用程序域(AppDomain) 浅析</title>
		<link>http://amberlife.net/2009/12/%e8%bf%9b%e7%a8%8b%e3%80%81%e7%ba%bf%e7%a8%8b%e4%b8%8e%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e5%9f%9fappdomain-%e6%b5%85%e6%9e%90/</link>
		<comments>http://amberlife.net/2009/12/%e8%bf%9b%e7%a8%8b%e3%80%81%e7%ba%bf%e7%a8%8b%e4%b8%8e%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e5%9f%9fappdomain-%e6%b5%85%e6%9e%90/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 04:38:04 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>

		<guid isPermaLink="false">http://amberlife.net/?p=163</guid>
		<description><![CDATA[进程
进程是操作系统用于隔离众多正在运行的应用程序的机制。在．Net之前，每一个应用程序被加载到单独的进程中，并为该进程指定私有的虚拟内存。进程不能直接访问物理内存，操作系统通过其它的处理把这些虚拟内存映射到物理内存或IO设备的某个区域，而这些物理内存之间不会有重叠，这就决定了一个进程不可能访问分配给另一个进程的内存。相应地，运行在该进程中的应用程序也不可能写入另一个应用程序的内存，这确保了任何执行出错的代码不会损害其地址空间以外的应用程序。在这种机制下，进程作为应用程序之间一个独立而安全的边界在很大程度上提高了运行安全。
 进程的缺点是降低了性能。许多一起工作的进程需要相互通信，而进程却不能共享任何内存，你不能通过任何有意义的方式使用从一个进程传递到另一个进程的内存指针。此外，你不能在两个进程间进行直接调用。你必须代之以使用代理，它提供一定程度的间接性。虽然，使用动态连接库dll让所有的组件运行在同一空间，一定程度上可以提高性能，但这些组件相互影响，一个组件的错误将极有可能导致整个应用程序的崩溃，“dll地狱”更是让许多应用程序难以避免。
线程
线程是进程中的一个实体，是被系统独立调度和分派的基本单位，线程自己不拥有系统资源，只拥有一点在运行中必不可少的资源，但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程，同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约，致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。
线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程.
线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定. 线程的运行中需要使用计算机的内存资源和CPU.
应用程序域(AppDomain)
在．Net中，应用程序有了一个新的边界：应用程序域（以下简称域）。它是一个用于隔离应用程序的虚拟边界。为了禁止不应交互的代码进行交互，这种隔离是必要的。．Net的应用程序在域层次上进行隔离，一个域中的应用程序不能直接访问另一个域中的代码和数据。这种隔离使得在一个应用程序范围内创建的所有对象都在一个域内创建，确保在同一进程中一个域内运行的代码不会影响其他域内的应用程序，大大提高了运行的安全。
.Net结构中，由于公共语言运行库能够验证代码是否为类型安全的代码，所以它可以提供与进程边界一样大的隔离级别，其性能开销也要低得多。你可以在单个进程中运行几个域，而不会造成进程间调用或切换等方面的额外开销。这种方法是把任何一个进程分解到多个域中，允许多个应用程序在同一进程中运行，每个域大致对应一个应用程序，运行的每个线程都在一个特殊的域中。如果不同的可执行文件都运行在同一个进程空间中，它们就能轻松地共享数据或直接访问彼此的数据。这种代码同运行同一个进程但域不同的类型安全代码一起运行时是安全的。在一个进程内运行多个应用程序的能力显著增强了服务器的可伸缩性。
域与线程的关系
在.Net中，线程是公共语言运行库用来执行代码的操作系统构造。在运行时，所有托管代码均加载到一个域中，由特定的操作系统线程来运行。然而，域和线程之间并不具有一一对应关系。在任意给定时间，单个域中可以执行不止一个线程，而且特定线程也并不局限在单个域内。也就是说，线程可以跨越域边界，不为每个域创建新线程。当然，在指定时刻，每一线程都只能在一个域中执行。运行库会跟踪所有域中有哪些线程正在运行。通过调用．Net类库的 Thread.GetDomain 方法，你还可以确定正在执行的线程所在的域。
&#60;转载自：http://www.cnblogs.com/Dlonghow/archive/2009/09/24/1573122.html&#62;
]]></description>
			<content:encoded><![CDATA[<p>进程<br />
进程是操作系统用于隔离众多正在运行的应用程序的机制。在．Net之前，每一个应用程序被加载到单独的进程中，并为该进程指定私有的虚拟内存。进程不能直接访问物理内存，操作系统通过其它的处理把这些虚拟内存映射到物理内存或IO设备的某个区域，而这些物理内存之间不会有重叠，这就决定了一个进程不可能访问分配给另一个进程的内存。相应地，运行在该进程中的应用程序也不可能写入另一个应用程序的内存，这确保了任何执行出错的代码不会损害其地址空间以外的应用程序。在这种机制下，进程作为应用程序之间一个独立而安全的边界在很大程度上提高了运行安全。</p>
<p><span id="more-163"></span> 进程的缺点是降低了性能。许多一起工作的进程需要相互通信，而进程却不能共享任何内存，你不能通过任何有意义的方式使用从一个进程传递到另一个进程的内存指针。此外，你不能在两个进程间进行直接调用。你必须代之以使用代理，它提供一定程度的间接性。虽然，使用动态连接库dll让所有的组件运行在同一空间，一定程度上可以提高性能，但这些组件相互影响，一个组件的错误将极有可能导致整个应用程序的崩溃，“dll地狱”更是让许多应用程序难以避免。<br />
线程<br />
线程是进程中的一个实体，是被系统独立调度和分派的基本单位，线程自己不拥有系统资源，只拥有一点在运行中必不可少的资源，但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程，同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约，致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。<br />
线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程.<br />
线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定. 线程的运行中需要使用计算机的内存资源和CPU.<br />
应用程序域(AppDomain)<br />
在．Net中，应用程序有了一个新的边界：应用程序域（以下简称域）。它是一个用于隔离应用程序的虚拟边界。为了禁止不应交互的代码进行交互，这种隔离是必要的。．Net的应用程序在域层次上进行隔离，一个域中的应用程序不能直接访问另一个域中的代码和数据。这种隔离使得在一个应用程序范围内创建的所有对象都在一个域内创建，确保在同一进程中一个域内运行的代码不会影响其他域内的应用程序，大大提高了运行的安全。</p>
<p>.Net结构中，由于公共语言运行库能够验证代码是否为类型安全的代码，所以它可以提供与进程边界一样大的隔离级别，其性能开销也要低得多。你可以在单个进程中运行几个域，而不会造成进程间调用或切换等方面的额外开销。这种方法是把任何一个进程分解到多个域中，允许多个应用程序在同一进程中运行，每个域大致对应一个应用程序，运行的每个线程都在一个特殊的域中。如果不同的可执行文件都运行在同一个进程空间中，它们就能轻松地共享数据或直接访问彼此的数据。这种代码同运行同一个进程但域不同的类型安全代码一起运行时是安全的。在一个进程内运行多个应用程序的能力显著增强了服务器的可伸缩性。<br />
域与线程的关系<br />
在.Net中，线程是公共语言运行库用来执行代码的操作系统构造。在运行时，所有托管代码均加载到一个域中，由特定的操作系统线程来运行。然而，域和线程之间并不具有一一对应关系。在任意给定时间，单个域中可以执行不止一个线程，而且特定线程也并不局限在单个域内。也就是说，线程可以跨越域边界，不为每个域创建新线程。当然，在指定时刻，每一线程都只能在一个域中执行。运行库会跟踪所有域中有哪些线程正在运行。通过调用．Net类库的 Thread.GetDomain 方法，你还可以确定正在执行的线程所在的域。<br />
&lt;转载自：http://www.cnblogs.com/Dlonghow/archive/2009/09/24/1573122.html&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2009/12/%e8%bf%9b%e7%a8%8b%e3%80%81%e7%ba%bf%e7%a8%8b%e4%b8%8e%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e5%9f%9fappdomain-%e6%b5%85%e6%9e%90/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>反射，动态加载，晚期绑定间的关系。</title>
		<link>http://amberlife.net/2009/12/%e5%8f%8d%e5%b0%84%ef%bc%8c%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%ef%bc%8c%e6%99%9a%e6%9c%9f%e7%bb%91%e5%ae%9a%e9%97%b4%e7%9a%84%e5%85%b3%e7%b3%bb%e3%80%82/</link>
		<comments>http://amberlife.net/2009/12/%e5%8f%8d%e5%b0%84%ef%bc%8c%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%ef%bc%8c%e6%99%9a%e6%9c%9f%e7%bb%91%e5%ae%9a%e9%97%b4%e7%9a%84%e5%85%b3%e7%b3%bb%e3%80%82/#comments</comments>
		<pubDate>Tue, 22 Dec 2009 01:36:16 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>

		<guid isPermaLink="false">http://amberlife.net/?p=161</guid>
		<description><![CDATA[1 动态加载程序集
2 反射获取Type信息（类的信息，方法的信息）
3晚期绑定（1 创造对象实例  2 调用方法（有参，无参））
]]></description>
			<content:encoded><![CDATA[<p>1 动态加载程序集</p>
<p>2 反射获取Type信息（类的信息，方法的信息）</p>
<p>3晚期绑定（1 创造对象实例  2 调用方法（有参，无参））</p>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2009/12/%e5%8f%8d%e5%b0%84%ef%bc%8c%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%ef%bc%8c%e6%99%9a%e6%9c%9f%e7%bb%91%e5%ae%9a%e9%97%b4%e7%9a%84%e5%85%b3%e7%b3%bb%e3%80%82/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>.net程序集格式</title>
		<link>http://amberlife.net/2009/12/net%e7%a8%8b%e5%ba%8f%e9%9b%86%e6%a0%bc%e5%bc%8f/</link>
		<comments>http://amberlife.net/2009/12/net%e7%a8%8b%e5%ba%8f%e9%9b%86%e6%a0%bc%e5%bc%8f/#comments</comments>
		<pubDate>Sun, 20 Dec 2009 08:36:00 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[高级编程技巧]]></category>

		<guid isPermaLink="false">http://amberlife.net/2009/12/net%e7%a8%8b%e5%ba%8f%e9%9b%86%e6%a0%bc%e5%bc%8f/</guid>
		<description><![CDATA[win32文件首部
CLR文件首部
CIL代码
类型元数据
程序集清单
可选的嵌入资源
]]></description>
			<content:encoded><![CDATA[<p>win32文件首部</p>
<p>CLR文件首部</p>
<p>CIL代码</p>
<p>类型元数据</p>
<p>程序集清单</p>
<p>可选的嵌入资源</p>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2009/12/net%e7%a8%8b%e5%ba%8f%e9%9b%86%e6%a0%bc%e5%bc%8f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>求二进制数中1的个数</title>
		<link>http://amberlife.net/2009/12/%e6%b1%82%e4%ba%8c%e8%bf%9b%e5%88%b6%e6%95%b0%e4%b8%ad1%e7%9a%84%e4%b8%aa%e6%95%b0/</link>
		<comments>http://amberlife.net/2009/12/%e6%b1%82%e4%ba%8c%e8%bf%9b%e5%88%b6%e6%95%b0%e4%b8%ad1%e7%9a%84%e4%b8%aa%e6%95%b0/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 16:16:44 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>
		<category><![CDATA[数据结构]]></category>

		<guid isPermaLink="false">http://amberlife.net/?p=156</guid>
		<description><![CDATA[对于一个字节（8bit）的变量，求其二进制表示中“1”的个数，要求算法的执行效率尽可能地高。
【解法一】
可以举一个八位的二进制例子来进行分析。对于二进制操作，我们知道，除以一个2，原来的数字将会减少一个0。如果除的过程中有余，那么就表示当前位置有一个1。
int Count(int v)
{
int num = 0;
while(v)
{
if(v % 2 == 1)
{
num++;
}
v = v/ 2;
}
return num;
}
【解法二】使用位操作
前面的代码看起来比较复杂。我们知道，向右移位操作同样也可以达到相除的目的。唯一不同之处在于，移位之后如何来判断是否有1存在。对于这个问题，再来看看一个八位的数字：10 100 001。
在向右移位的过程中，我们会把最后一位直接丢弃。因此，需要判断最后一位是否为1，而“与”操作可以达到目的。可以把这个八位的数字与00000001进行“与”操作。如果结果为1，则表示当前八位数的最后一位为1，否则为0。代码如下：
int Count(int v)
{
int num = 0;
While(v)
{
num += v &#38;0&#215;01;
v &#62;&#62;= 1;
}
return num;
}
【解法三】
位操作比除、余操作的效率高了很多。但是，即使采用位操作，时间复杂度仍为O（log2v），log2v为二进制数的位数。那么，还能不能再降低一些复杂度呢？如果有办法让算法的复杂度只与“1”的个数有关，复杂度不就能进一步降低了吗？
同样用10 100 001来举例。如果只考虑和1的个数相关，那么，我们是否能够在每次判断中，仅与1来进行判断呢？
为了简化这个问题，我们考虑只有一个1的情况。例如：01 000 000。
如何判断给定的二进制数里面有且仅有一个1呢？可以通过判断这个数是否是2的整数次幂来实现。另外，如果只和这一个“1”进行判断，如何设计操作呢？我们知道的是，如果进行这个操作，结果为0或为1，就可以得到结论。
int Count(int v)
{
int num = 0;
while(v)
{
v &#38;= (v-1);
num++;
}
return num;
}
【解法五】查表法
int countTable[256] =
{
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, [...]]]></description>
			<content:encoded><![CDATA[<p>对于一个字节（8bit）的变量，求其二进制表示中“1”的个数，要求算法的执行效率尽可能地高。<span id="more-156"></span></p>
<p>【解法一】</p>
<p>可以举一个八位的二进制例子来进行分析。对于二进制操作，我们知道，除以一个2，原来的数字将会减少一个0。如果除的过程中有余，那么就表示当前位置有一个1。</p>
<p>int Count(int v)</p>
<p>{</p>
<p>int num = 0;</p>
<p>while(v)</p>
<p>{</p>
<p>if(v % 2 == 1)</p>
<p>{</p>
<p>num++;</p>
<p>}</p>
<p>v = v/ 2;</p>
<p>}</p>
<p>return num;</p>
<p>}</p>
<p>【解法二】使用位操作</p>
<p>前面的代码看起来比较复杂。我们知道，向右移位操作同样也可以达到相除的目的。唯一不同之处在于，移位之后如何来判断是否有1存在。对于这个问题，再来看看一个八位的数字：10 100 001。</p>
<p>在向右移位的过程中，我们会把最后一位直接丢弃。因此，需要判断最后一位是否为1，而“与”操作可以达到目的。可以把这个八位的数字与00000001进行“与”操作。如果结果为1，则表示当前八位数的最后一位为1，否则为0。代码如下：</p>
<p>int Count(int v)</p>
<p>{</p>
<p>int num = 0;</p>
<p>While(v)</p>
<p>{</p>
<p>num += v &amp;0&#215;01;</p>
<p>v &gt;&gt;= 1;</p>
<p>}</p>
<p>return num;</p>
<p>}</p>
<p>【解法三】</p>
<p>位操作比除、余操作的效率高了很多。但是，即使采用位操作，时间复杂度仍为O（log2v），log2v为二进制数的位数。那么，还能不能再降低一些复杂度呢？如果有办法让算法的复杂度只与“1”的个数有关，复杂度不就能进一步降低了吗？</p>
<p>同样用10 100 001来举例。如果只考虑和1的个数相关，那么，我们是否能够在每次判断中，仅与1来进行判断呢？</p>
<p>为了简化这个问题，我们考虑只有一个1的情况。例如：01 000 000。</p>
<p>如何判断给定的二进制数里面有且仅有一个1呢？可以通过判断这个数是否是2的整数次幂来实现。另外，如果只和这一个“1”进行判断，如何设计操作呢？我们知道的是，如果进行这个操作，结果为0或为1，就可以得到结论。</p>
<p>int Count(int v)</p>
<p>{</p>
<p>int num = 0;</p>
<p>while(v)</p>
<p>{</p>
<p>v &amp;= (v-1);</p>
<p>num++;</p>
<p>}</p>
<p>return num;</p>
<p>}</p>
<p>【解法五】查表法</p>
<p>int countTable[256] =</p>
<p>{</p>
<p>0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,</p>
<p>3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3,</p>
<p>4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,</p>
<p>3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3,</p>
<p>4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6,</p>
<p>6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,</p>
<p>5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,</p>
<p>3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3,</p>
<p>4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4,</p>
<p>4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6,</p>
<p>7, 6, 7, 7, 8</p>
<p>};</p>
<p>int Count(int v)</p>
<p>{</p>
<p>//check parameter</p>
<p>return countTable[v];</p>
<p>}</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/jiju8484/archive/2008/04/03/2247823.aspx</p>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2009/12/%e6%b1%82%e4%ba%8c%e8%bf%9b%e5%88%b6%e6%95%b0%e4%b8%ad1%e7%9a%84%e4%b8%aa%e6%95%b0/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>c#中变量的初始化</title>
		<link>http://amberlife.net/2009/11/csharpvariable/</link>
		<comments>http://amberlife.net/2009/11/csharpvariable/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 11:46:48 +0000</pubDate>
		<dc:creator>amberlife</dc:creator>
				<category><![CDATA[program]]></category>

		<guid isPermaLink="false">http://amberlife.net/?p=146</guid>
		<description><![CDATA[在c#中变量在未明确赋值之前，变量拥有一个所属类型的等价于0的值。在正确理解c#中初始化的概念的时候，我们必须区分局部变量(local variable)——在一个方法内部声明的变量，它的作用范围被局限在此方法内；类的字段(fields of a class)的区别

所有的局部变量，再被代码明确的初始化之前，都会被编译器看作未初始化


所有的字段在被自动初始化为所属类型中等价于0的值。如布尔型的被初始化为false，数值型被初始化为0或者0.0，所有的引用类型都被初始化为null。

public class Student
{
//字段部分
private int age;//初始化为0
private double gpa; //初始化为0.0
private bool isHonorsStudent; //初始化为null
//这也包括静态变量
private static int studentCount; //初始化为0
//方法
public void UpdateGPA()
{
double val;//未初始化
String course;//未初始化
}
}
]]></description>
			<content:encoded><![CDATA[<p>在c#中变量在未明确赋值之前，变量拥有一个所属类型的等价于0的值。在正确理解c#中初始化的概念的时候，我们必须区分局部变量(local variable)——在一个方法内部声明的变量，它的作用范围被局限在此方法内；类的字段(fields of a class)的区别<span id="more-146"></span></p>
<ul>
<li>所有的局部变量，再被代码明确的初始化之前，都会被编译器看作未初始化</li>
</ul>
<ul>
<li>所有的字段在被自动初始化为所属类型中等价于0的值。如布尔型的被初始化为false，数值型被初始化为0或者0.0，所有的引用类型都被初始化为null。</li>
</ul>
<p>public class Student<br />
{<br />
//字段部分<br />
private int age;//初始化为0<br />
private double gpa; //初始化为0.0<br />
private bool isHonorsStudent; //初始化为null<br />
//这也包括静态变量<br />
private static int studentCount; //初始化为0</p>
<p>//方法<br />
public void UpdateGPA()<br />
{<br />
double val;//未初始化<br />
String course;//未初始化<br />
}<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://amberlife.net/2009/11/csharpvariable/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
