当前位置:文档之家› 秒杀多线程系列

秒杀多线程系列

秒杀多线程系列
秒杀多线程系列

秒杀多线程

系列

目录

系列前言 (2)

秒杀多线程第一篇多线程笔试面试题汇总 (2)

一.概念性问答题 (2)

二.选择题 (3)

三.综合题 (3)

秒杀多线程第二篇多线程第一次亲密接触 CreateThread与_beginthreadex本质区别 (4)

秒杀多线程第三篇原子操作 Interlocked系列函数 (12)

秒杀多线程第四篇一个经典的多线程同步问题 (17)

秒杀多线程第五篇经典线程同步关键段CS (20)

秒杀多线程第六篇经典线程同步事件Event (25)

秒杀多线程第七篇经典线程同步互斥量Mutex (32)

秒杀多线程第八篇经典线程同步信号量Semaphore (38)

秒杀多线程第九篇经典线程同步总结关键段事件互斥量信号量 (42)

秒杀多线程第十篇生产者消费者问题 (44)

秒杀多线程第十一篇读者写者问题 (52)

秒杀多线程第十二篇多线程同步内功心法——PV操作上 (58)

秒杀多线程第十四篇读者写者问题继读写锁SRWLock (61)

本系列是本人参加微软亚洲研究院,腾讯研究院,迅雷面试时整理的,另外也加入一些其它IT公司如百度,阿里巴巴的笔试面试题目,因此具有很强的针对性。系列中不但会详细讲解多线程同步互斥的各种“招式”,而且会进一步的讲解多线程同步互斥的“内功心法”。有了“招式”和“内功心法”,相信你也能对多线程挥洒自如,在笔试面试中顺

利的秒杀多线程试题。

秒杀多线程第一篇多线程笔试面试题汇总

多线程在笔试面试中经常出现,下面列出一些公司的多线程笔试面试题。首先是一些概念性的问答题,这些是多线程的基础知识,经常出现在面试中的第一轮面试(我参加2011年腾讯研究院实习生招聘时就被问到了几个概念性题目)。然后是一些选择题,这些一般在笔试时出现,虽然不是太难,但如果在选择题上花费大多时间无疑会对后面的编程题造成影响,因此必须迅速的解决掉。最后是综合题即难一些的问答题或是编程题。这种题目当然是最难解决了,要么会引来面试官的追问,要么就很容易考虑不周全,因此解决这类题目时一定要考虑全面和细致。

下面就来看看这三类题目吧。

一.概念性问答题

第一题:线程的基本概念、线程的基本状态及状态之间的关系?

第二题:线程与进程的区别?

这个题目问到的概率相当大,计算机专业考研中也常常考到。要想全部答出比较难。第三题:多线程有几种实现方法,都是什么?

第四题:多线程同步和互斥有几种实现方法,都是什么?

我在参加2011年迅雷校园招聘时的一面和二面都被问到这个题目,回答的好将会给面试成绩加不少分。

第五题:多线程同步和互斥有何异同,在什么情况下分别使用他们?举例说明。

第一题(百度笔试题):

以下多线程对int型变量x的操作,哪几个不需要进行同步:

A. x=y;

B. x++;

C. ++x;

D. x=1;

第二题(阿里巴巴笔试题)

多线程中栈与堆是公有的还是私有的

A:栈公有, 堆私有

B:栈公有,堆公有

C:栈私有, 堆公有

D:栈私有,堆私有

三.综合题

第一题(台湾某杀毒软件公司面试题):

在Windows编程中互斥量与临界区比较类似,请分析一下二者的主要区别。

第二题:

一个全局变量tally,两个线程并发执行(代码段都是ThreadProc),问两个线程都结束后,tally取值范围。

inttally = 0;//glable

void ThreadProc()

{

for(inti = 1; i <= 50; i++)

tally += 1;

}

第三题(某培训机构的练习题):

子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主

线程又循环 100 次,如此循环50次,试写出代码。

第四题(迅雷笔试题):

编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID

在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。第五题(Google面试题)

有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:

A:1 2 3 4 1 2....

B:2 3 4 1 2 3....

C:3 4 1 2 3 4....

D:4 1 2 3 4 1....

请设计程序。

下面的第六题与第七题也是在考研中或是程序员和软件设计师认证考试中的热门试题。第六题

生产者消费者问题

这是一个非常经典的多线程题目,题目大意如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,所有生产者和消费者都是异步方式运行的,但它们必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经装满产品且尚未被取走的缓冲区中投放产品。

第七题

读者写者问题

这也是一个非常经典的多线程题目,题目大意如下:有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写。

秒杀多线程第二篇多线程第一次亲密接触 CreateThread与

_beginthreadex本质区别

本文将带领你与多线程作第一次亲密接触,并深入分析CreateThread与_beginthreadex 的本质区别,相信阅读本文后你能轻松的使用多线程并能流畅准确的回答CreateThread与_beginthreadex到底有什么区别,在实际的编程中到底应该使用CreateThread还是

_beginthreadex?

使用多线程其实是非常容易的,下面这个程序的主线程会创建了一个子线程并等待其运行完毕,子线程就输出它的线程ID号然后输出一句经典名言——Hello World。整个程序的代码非常简短,只有区区几行。

1.//最简单的创建多线程实例

2.#include

3.#include

4.//子线程函数

5.DWORD WINAPI ThreadFun(LPVOID pM)

6.{

7. printf("子线程的线程ID号为:%d\n子线程输出Hello World\n", GetCurrentThreadId());

8.return 0;

9.}

10.//主函数,所谓主函数其实就是主线程执行的函数。

11.int main()

12.{

13. printf(" 最简单的创建多线程实例\n");

14. printf(" -- by MoreWindows( https://www.doczj.com/doc/6c5938905.html,/MoreWindows ) --\n\n");

15.

16.HANDLE handle = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);

17. WaitForSingleObject(handle, INFINITE);

18.return 0;

19.}

运行结果如下所示:

下面来细讲下代码中的一些函数

第一个CreateThread

函数功能:创建线程

函数原型:

HANDLE WINAPI CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes,

SIZE_T dwStackSize,

LPTHREAD_START_ROUTINE lpStartAddress,

LPVOID lpParameter,

DWORD dwCreationFlags,

LPDWORD lpThreadId

);

函数说明:

第一个参数表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。

第二个参数表示线程栈空间大小。传入0表示使用默认大小(1MB)。

第三个参数表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。

第四个参数是传给线程函数的参数。

第五个参数指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()。

第六个参数将返回线程的ID号,传入NULL表示不需要返回该线程ID号。

函数返回值:

成功返回新线程的句柄,失败返回NULL。

第二个WaitForSingleObject

函数功能:等待函数–使线程进入等待状态,直到指定的内核对象被触发。

函数原形:

DWORD WINAPI WaitForSingleObject(

HANDLE hHandle,

DWORD dwMilliseconds

);

函数说明:

第一个参数为要等待的内核对象。

第二个参数为最长等待的时间,以毫秒为单位,如传入5000就表示5秒,传入0就立即返回,传入INFINITE表示无限等待。

因为线程的句柄在线程运行时是未触发的,线程结束运行,句柄处于触发状态。所以可以用WaitForSingleObject()来等待一个线程结束运行。

函数返回值:

在指定的时间内对象被触发,函数返回WAIT_OBJECT_0。超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。传入参数有错误将返回WAIT_FAILED

CreateThread()函数是Windows提供的API接口,在C/C++语言另有一个创建线程的函数_beginthreadex(),在很多书上(包括《Windows核心编程》)提到过尽量使用

_beginthreadex()来代替使用CreateThread(),这是为什么了?下面就来探索与发现它们的区别吧。

首先要从标准C运行库与多线程的矛盾说起,标准C运行库在1970年被实现了,由于当时没任何一个操作系统提供对多线程的支持。因此编写标准C运行库的程序员根本没考虑多线程程序使用标准C运行库的情况。比如标准C运行库的全局变量errno。很多运行库中的函数在出错时会将错误代号赋值给这个全局变量,这样可以方便调试。但如果有这样的一个代码片段:

20.if (system("notepad.exe readme.txt") == -1)

21.{

22.switch(errno)

23. {

24. ...//错误处理代码

25. }

26.}

假设某个线程A在执行上面的代码,该线程在调用system()之后且尚未调用switch()语句时另外一个线程B启动了,这个线程B也调用了标准C运行库的函数,不幸的是这个函数执行出错了并将错误代号写入全局变量errno中。这样线程A一旦开始执行switch()语句时,它将访问一个被B线程改动了的errno。这种情况必须要加以避免!因为不单单是这一个变量会出问题,其它像strerror()、strtok()、tmpnam()、gmtime()、asctime()等函数也会遇到这种由多个线程访问修改导致的数据覆盖问题。

为了解决这个问题,Windows操作系统提供了这样的一种解决方案——每个线程都将拥有自己专用的一块内存区域来供标准C运行库中所有有需要的函数使用。而且这块内存区域的创建就是由C/C++运行库函数_beginthreadex()来负责的。下面列出_beginthreadex()函数的源代码(我在这份代码中增加了一些注释)以便读者更好的理解_beginthreadex()函数与CreateThread()函数的区别。

27.//_beginthreadex源码整理By MoreWindows( https://www.doczj.com/doc/6c5938905.html,/MoreWindows )

28._MCRTIMP uintptr_t __cdecl _beginthreadex(

29.void *security,

30. unsigned stacksize,

31. unsigned (__CLR_OR_STD_CALL * initialcode) (void *),

32.void * argument,

33. unsigned createflag,

34. unsigned *thrdaddr

35.)

36.{

37. _ptiddata ptd; //pointer to per-thread data 见注1

38.uintptr_t thdl; //thread handle 线程句柄

39. unsigned long err = 0L; //Return from GetLastError()

40. unsigned dummyid; //dummy returned thread ID 线程ID号

41.

42.// validation section 检查initialcode是否为NULL

43. _VALIDATE_RETURN(initialcode != NULL, EINVAL, 0);

44.

45.//Initialize FlsGetValue function pointer

46. __set_flsgetvalue();

47.

48.//Allocate and initialize a per-thread data structure for the to-be-created thread.

49.//相当于new一个_tiddata结构,并赋给_ptiddata指针。

50.if ( (ptd = (_ptiddata)_calloc_crt(1, sizeof(struct _tiddata))) == NULL )

51.goto error_return;

52.

53.// Initialize the per-thread data

54.//初始化线程的_tiddata块即CRT数据区域见注2

55. _initptd(ptd, _getptd()->ptlocinfo);

56.

57.//设置_tiddata结构中的其它数据,这样这块_tiddata块就与线程联系在一起了。

58. ptd->_initaddr = (void *) initialcode; //线程函数地址

59. ptd->_initarg = argument; //传入的线程参数

60. ptd->_thandle = (uintptr_t)(-1);

61.

62.#if defined (_M_CEE) || defined (MRTDLL)

63.if(!_getdomain(&(ptd->__initDomain))) //见注3

64. {

65.goto error_return;

66. }

67.#endif // defined (_M_CEE) || defined (MRTDLL)

68.

69.// Make sure non-NULL thrdaddr is passed to CreateThread

70.if ( thrdaddr == NULL )//判断是否需要返回线程ID号

71. thrdaddr = &dummyid;

72.

73.// Create the new thread using the parameters supplied by the caller.

74.//_beginthreadex()最终还是会调用CreateThread()来向系统申请创建线程

75.if ( (thdl = (uintptr_t)CreateThread(

76. (LPSECURITY_ATTRIBUTES)security,

77. stacksize,

78. _threadstartex,

79. (LPVOID)ptd,

80. createflag,

81. (LPDWORD)thrdaddr))

82. == (uintptr_t)0 )

83. {

84. err = GetLastError();

85.goto error_return;

86. }

87.

88.//Good return

89.return(thdl); //线程创建成功,返回新线程的句柄.

90.

91.//Error return

92.error_return:

93.//Either ptd is NULL, or it points to the no-longer-necessary block

94.//calloc-ed for the _tiddata struct which should now be freed up.

95.//回收由_calloc_crt()申请的_tiddata块

96. _free_crt(ptd);

97.// Map the error, if necessary.

98.// Note: this routine returns 0 for failure, just like the Win32

99.// API CreateThread, but _beginthread() returns -1 for failure.

100.//校正错误代号(可以调用GetLastError()得到错误代号)

101.if ( err != 0L )

102. _dosmaperr(err);

103.return( (uintptr_t)0 ); //返回值为NULL的效句柄

104.}

讲解下部分代码:

注1._ptiddata ptd;中的_ptiddata是个结构体指针。在mtdll.h文件被定义:

typedefstruct_tiddata * _ptiddata

微软对它的注释为Structure for each thread's data。这是一个非常大的结构体,有很多成员。本文由于篇幅所限就不列出来了。

注2._initptd(ptd, _getptd()->ptlocinfo);微软对这一句代码中的getptd()的说明为:/* return address of per-thread CRT data */

_ptiddata __cdecl_getptd(void);

对_initptd()说明如下:

/* initialize a per-thread CRT data block */

void__cdecl_initptd(_Inout_ _ptiddata _Ptd,_In_opt_ pthreadlocinfo _Locale);

注释中的CRT (C Runtime Library)即标准C运行库。

注3.if(!_getdomain(&(ptd->__initDomain)))中的_getdomain()函数代码可以在thread.c文件中找到,其主要功能是初始化COM环境。

由上面的源代码可知,_beginthreadex()函数在创建新线程时会分配并初始化一个_tiddata 块。这个_tiddata块自然是用来存放一些需要线程独享的数据。事实上新线程运行时会首先将_tiddata块与自己进一步关联起来。然后新线程调用标准C运行库函数如strtok()时就会先取得_tiddata块的地址再将需要保护的数据存入_tiddata块中。这样每个线程就只会访问和修改自己的数据而不会去篡改其它线程的数据了。因此,如果在代码中有使用标准C 运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()。相信阅读到这里时,你会对这句简短的话有个非常深刻的印象,如果有面试官问起,你也可以流畅准确的回答了^_^。

接下来,类似于上面的程序用CreateThread()创建输出“Hello World”的子线程,下面使用_beginthreadex()来创建多个子线程:

105.//创建多子个线程实例

106.#include

107.#include

108.#include

109.//子线程函数

110.unsigned int __stdcall ThreadFun(PVOID pM)

111.{

112. printf("线程ID号为%4d的子线程说:Hello World\n", GetCurrentThreadId());

113.return 0;

114.}

115.//主函数,所谓主函数其实就是主线程执行的函数。

116.int main()

117.{

118. printf(" 创建多个子线程实例 \n");

119. printf(" -- by MoreWindows( https://www.doczj.com/doc/6c5938905.html,/MoreWindows ) --\n\n");

120.

121.const int THREAD_NUM = 5;

122.HANDLE handle[THREAD_NUM];

123.for (int i = 0; i < THREAD_NUM; i++)

124. handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);

125. WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);

126.return 0;

127.}

运行结果如下:

图中每个子线程说的都是同一句话,不太好看。能不能来一个线程报数功能,即第一个子线程输出1,第二个子线程输出2,第三个子线程输出3,……。要实现这个功能似乎非常简单——每个子线程对一个全局变量进行递增并输出就可以了。代码如下:128.//子线程报数

129.#include

130.#include

131.#include

132.int g_nCount;

133.//子线程函数

134.unsigned int __stdcall ThreadFun(PVOID pM)

135.{

136. g_nCount++;

137. printf("线程ID号为%4d的子线程报数%d\n", GetCurrentThreadId(), g_nCount);

138.return 0;

139.}

140.//主函数,所谓主函数其实就是主线程执行的函数。

141.int main()

142.{

143. printf(" 子线程报数 \n");

144. printf(" -- by MoreWindows( https://www.doczj.com/doc/6c5938905.html,/MoreWindows ) --\n\n");

145.

146.const int THREAD_NUM = 10;

147.HANDLE handle[THREAD_NUM];

148.

149. g_nCount = 0;

150.for (int i = 0; i < THREAD_NUM; i++)

151. handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);

152. WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);

153.return 0;

154.}

对一次运行结果截图如下:

显示结果从1数到10,看起来好象没有问题。

答案是不对的,虽然这种做法在逻辑上是正确的,但在多线程环境下这样做是会产生严重的问题,下一篇《秒杀多线程第三篇原子操作 Interlocked系列函数》将为你演示错误的结果(可能非常出人意料)并解释产生这个结果的详细原因。

秒杀多线程第三篇原子操作 Interlocked系列函数

上一篇《多线程第一次亲密接触 CreateThread与_beginthreadex本质区别》中讲到一个多线程报数功能。为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是否运行出错。这也非常类似于统计一个网站每天有多少用户登录,每个用户登录用一个线程模拟,线程运行时会将一个表示计数的变量递增。程序在最后输出计数的值表示有今天多少个用户登录,如果这个值不等于我们启动的线程个数,那显然说明这个程序是有问题的。整个程序代码如下:

1.#include

2.#include

3.#include

4.volatile long g_nLoginCount; //登录次数

5.unsigned int __stdcall Fun(void *pPM); //线程函数

6.const int THREAD_NUM = 10; //启动线程数

7.unsigned int __stdcall ThreadFun(void *pPM)

8.{

9. Sleep(100); //some work should to do

10. g_nLoginCount++;

11. Sleep(50);

12.return 0;

13.}

14.int main()

15.{

16. g_nLoginCount = 0;

17.

18.HANDLE handle[THREAD_NUM];

19.for (int i = 0; i < THREAD_NUM; i++)

20. handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);

21.

22. WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);

23. printf("有%d个用户登录后记录结果是%d\n", THREAD_NUM, g_nLoginCount);

24.return 0;

25.}

程序中模拟的是10个用户登录,程序将输出结果:

和上一篇的线程报数程序一样,程序输出的结果好象并没什么问题。下面我们增加点用户来试试,现在模拟50个用户登录,为了便于观察结果,在程序中将50个用户登录过程重复20次,代码如下:

26.#include

27.#include

28.volatile long g_nLoginCount; //登录次数

29.unsigned int __stdcall Fun(void *pPM); //线程函数

30.const DWORD THREAD_NUM = 50;//启动线程数

31.DWORD WINAPI ThreadFun(void *pPM)

32.{

33. Sleep(100); //some work should to do

34. g_nLoginCount++;

35. Sleep(50);

36.return 0;

37.}

38.int main()

39.{

40. printf(" 原子操作 Interlocked系列函数的使用\n");

41. printf(" -- by MoreWindows( https://www.doczj.com/doc/6c5938905.html,/MoreWindows ) --\n\n");

42.

43.//重复20次以便观察多线程访问同一资源时导致的冲突

44.int num= 20;

45.while (num--)

46. {

47. g_nLoginCount = 0;

48.int i;

49.HANDLE handle[THREAD_NUM];

50.for (i = 0; i < THREAD_NUM; i++)

51. handle[i] = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);

52. WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);

53. printf("有%d个用户登录后记录结果是%d\n", THREAD_NUM, g_nLoginCount);

54. }

55.return 0;

56.}

运行结果如下图:

现在结果水落石出,明明有50个线程执行了g_nLoginCount++;操作,但结果输出是不确定的,有可能为50,但也有可能小于50。

要解决这个问题,我们就分析下g_nLoginCount++;操作。在VC6.0编译器对

g_nLoginCount++;这一语句打个断点,再按F5进入调试状态,然后按下Debug工具栏的

Disassembly按钮,这样就出现了汇编代码窗口。可以发现在C/C++语言中一条简单的自增语句其实是由三条汇编代码组成的,如下图所示。

讲解下这三条汇编意思:

第一条汇编将g_nLoginCount的值从内存中读取到寄存器eax中。

第二条汇编将寄存器eax中的值与1相加,计算结果仍存入寄存器eax中。

第三条汇编将寄存器eax中的值写回内存中。

这样由于线程执行的并发性,很可能线程A执行到第二句时,线程B开始执行,线程B将原来的值又写入寄存器eax中,这样线程A所主要计算的值就被线程B修改了。这样执行下来,结果是不可预知的——可能会出现50,可能小于50。

因此在多线程环境中对一个变量进行读写时,我们需要有一种方法能够保证对一个值的递增操作是原子操作——即不可打断性,一个线程在执行原子操作时,其它线程必须等待它完成之后才能开始执行该原子操作。这种涉及到硬件的操作会不会很复杂了,幸运的是,Windows系统为我们提供了一些以Interlocked开头的函数来完成这一任务(下文将这些函数称为Interlocked系列函数)。

下面列出一些常用的Interlocked系列函数:

1.增减操作

LONG__cdecl InterlockedIncrement(LONG volatile* Addend);

LONG__cdecl InterlockedDecrement(LONG volatile* Addend);

返回变量执行增减操作之后的值。

LONG__cdec InterlockedExchangeAdd(LONG volatile* Addend, LONG Value);

返回运算后的值,注意!加个负数就是减。

2.赋值操作

LONG__cdecl InterlockedExchange(LONG volatile* Target, LONG Value);

Value就是新值,函数会返回原先的值。

在本例中只要使用InterlockedIncrement()函数就可以了。将线程函数代码改成:

57.DWORD WINAPI ThreadFun(void *pPM)

58.{

59. Sleep(100);//some work should to do

60.//g_nLoginCount++;

61. InterlockedIncrement((LPLONG)&g_nLoginCount);

62. Sleep(50);

63.return 0;

64.}

再次运行,可以发现结果会是唯一的。

因此,在多线程环境下,我们对变量的自增自减这些简单的语句也要慎重思考,防止多个线程导致的数据访问出错。更多介绍,请访问MSDN上Synchronization Functions这一章节,地址为https://www.doczj.com/doc/6c5938905.html,/zh-cn/library/aa909196.aspx

看到这里,相信本系列首篇《秒杀多线程第一篇多线程笔试面试题汇总》中选择题第一题(百度笔试题)应该可以秒杀掉了吧(知其然也知其所以然),正确答案是D。另外给个附加问题,程序中是用50个线程模拟用户登录,有兴趣的同学可以试下用100个线程来模拟一下(上机试试绝对会有意外发现^_^)。

下一篇《秒杀多线程第四篇一个经典多线程同步问题》将提出一个稍为复杂点但却非常经典的多线程同步互斥问题,这个问题会采用不同的方法来解答,从而让你充分熟练多线程同步互斥的“招式”。更多精彩,欢迎继续参阅。

秒杀多线程第四篇一个经典的多线程同步问题

上一篇《秒杀多线程第三篇原子操作 Interlocked系列函数》中介绍了原子操作在多进程中的作用,现在来个复杂点的。这个问题涉及到线程的同步和互斥,是一道非常有代表性的多线程同步问题,如果能将这个问题搞清楚,那么对多线程同步也就打下了良好的基础。

程序描述:

主线程启动10个子线程并将表示子线程序号的变量地址作为参数传递给子线程。子线程接收参数 -> sleep(50) -> 全局变量++ -> sleep(0) -> 输出参数和全局变量。

要求:

1.子线程输出的线程序号不能重复。

2.全局变量的输出必须递增。

下面画了个简单的示意图:

分析下这个问题的考察点,主要考察点有二个:

1.主线程创建子线程并传入一个指向变量地址的指针作参数,由于线程启动须要花费一定的时间,所以在子线程根据这个指针访问并保存数据前,主线程应等待子线程保存完毕后才能改动该参数并启动下一个线程。这涉及到主线程与子线程之间的同步。

2.子线程之间会互斥的改动和输出全局变量。要求全局变量的输出必须递增。这涉及到各子线程间的互斥。

下面列出这个程序的基本框架,可以在此代码基础上进行修改和验证。

1.//经典线程同步互斥问题

2.#include

3.#include

4.#include

5.

6.long g_nNum; //全局资源

7.unsigned int __stdcall Fun(void *pPM); //线程函数

8.const int THREAD_NUM = 10; //子线程个数

9.

10.int main()

11.{

12. g_nNum = 0;

13.HANDLE handle[THREAD_NUM];

14.

15.int i = 0;

16.while (i < THREAD_NUM)

17. {

18. handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);

19. i++;//等子线程接收到参数时主线程可能改变了这个i的值

20. }

21.//保证子线程已全部运行结束

22. WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);

23.return 0;

24.}

25.

26.unsigned int __stdcall Fun(void *pPM)

27.{

28.//由于创建线程是要一定的开销的,所以新线程并不能第一时间执行到这来

29.int nThreadNum = *(int *)pPM; //子线程获取参数

30. Sleep(50);//some work should to do

31. g_nNum++; //处理全局资源

32. Sleep(0);//some work should to do

33. printf("线程编号为%d 全局资源值为%d\n", nThreadNum, g_nNum);

34.return 0;

35.}

运行结果可以参考下列图示,强烈建议读者亲自试一试。图1

图2

图3

高中英语语法重点难点回顾

高中英语语法重点难点回顾 ?主谓一致常考难题: Five minutes is enoughto do this exercise.?Each boy and each girl wants to servethe people in future.?More than one student has se en the film. ?Many a ship has been damaged in the storm.?More members than oneare against your plan.?一些有两个部分构成的名词表示衣物或工具作主语时,谓语通常用复数形式:glasses, clothes, trousers,shoes, compasse s, chopsticks, scissors等。 但如果主语用a kind of, apair of, a series of等加名词构成时, 谓语动词一般用单数形式。A pair of shoes was on the desk. 并列主语如果指的是同一个人、同一事物或同一概念时, 谓语动词用单数形式, 这时and 后面的名词没有冠词。例如: Truthand honesty is the best policy.?The girl’steacher and fri end is a young doctor. To love and tobeloved is the great happiness.?Goingto bede arlyand getting up earlyis a goodhabit.?A knifeandf ork is onthetable. 当主语后面跟有as wellas, asmuch as , no less than, alongwith, w ith,like, rather than, together with, but, except, besides,including, in addition to等引导的词组时, 其谓语动词的单、复数按主语的单、复数而定。例如: The teacheras well as the students was excited.?The room with its furniture was rented.?A (great)number of修饰可数复数名词, 谓语动词用复数; a great deal of,a largeamount of 修饰不可数名词, 其短语作主语时,谓语动词用单数。 关系代词who, that, which等在定语从句中作主语时, 其谓语动词的数应与句中先行词的数一致。例如: Those who want to go please sign your names here. Some of the energy that is used by man comes from thesun. 季节、月份、星期、节日、假日、一日三餐、学科名称,球类、棋类名词名称前一般不加冠1/2 one(a)half 1/4 one(a)quarter 词。? 形容词的顺序: 系动词be,grow,get,become,feel,appear,prove,seem,look,keep,smell,t aste,sound,turn,remain限定词+数量形容词(序数词在前,基数词在后)+性状形容词+大小、长短、高低等形体+新旧+颜色+国藉+材料?Those three beautiful large squ are old brown woodtable?某些以a-开首的形容词例如:afraid,alike,alone,asleep,awake, alive 等只能作表语,不能作定语。 某些以-ly结尾的词是形容词而不是副词:friendly,lively, lovely,lonely,likely,deadly,silly,orderly, timely等。?1)close接近地 closely仔细地,密切地?2)free免费地freely自由地,无拘束地 3)hard努力地 hardly几乎不 4)late 晚,迟lately 近来?5)most 极,非常mostly主要地?6)wide广阔地,充分地 widely广泛地?7)high高 highly高度地,非常地 8)deep深,迟 deeply抽象意义的“深”

(完整版)北师大版高中英语必修三U7知识点

1.keep …in mind =bear …in mind 记住 be in one’s mind 有……想法,想念…… be on one’s mind 压在心头,有心事 bring (back) to mind 使……想起 change one’s mind=alter one’s mind改变主意 keep one’s mind on 专心于……,聚精会神做…… make up one’s mind to do sth. 下决心,决定 to one’s mind 照……看来 be of one mind(=be of the same mind) 想法一致,同心同德 mind one’s own business 少管闲事 never mind 没关系;别介意 例子:(1)I have tried to keep his advice in mind when writing this book. (2) I think I know what is in your mind. (3) Please tell me what is on your mind. (4)The story you have just told brings to mind a strange thing that happened to me. (5)Nothing could change his mind, so the meeting broke up. (6) I found it hard to keep my mind on what he was saying. (7)Have you made up your mind to do what I told you? (8)I’m surprised at his doing such things; it’s dishonest, to my mind. 2.as …as possible=as …as sb. can尽量 Please be as kind to her as possible. Please be as kind to her as you can. 3.participate vi. 参加,参与;分享 participate with sb. in sth. 与某人分享/分担…… participant n. 参加者,参与者 participating adj. 由多人(或多方)一起参加的 participation n. 参与,参加,分享 participatory adj。提供参加机会的,供人分享的 He participates with us in our sufferings. 4.will / shall be doing

Java多线程技术及案例

Java多线程技术及案例 进程和线程: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。 线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。 多进程是指操作系统能同时运行多个任务(程序)。 多线程是指在同一程序中有多个顺序流在执行。 Java中多线程的多种实现方式 Java中有多种多线程实现方法,主要是继承https://www.doczj.com/doc/6c5938905.html,ng.Thread类的方法和 https://www.doczj.com/doc/6c5938905.html,ng.Runnable接口的方法。 继承Thread类 Thread是https://www.doczj.com/doc/6c5938905.html,ng包中的一个类,从这个类中实例化的对象代表线程,启动一个新线程需要建立一个Thread实例。 使用Thread类启动新的线程的步骤如下: 1.实例化Thread对象 2.调用start()方法启动线程 构造方法:

public Thread(String threadName); public Thread(); 例程: publicclass Thread1extends Thread{//定义一个类继承Thread privateint count=1000; publicvoid run(){//重写run方法 while(true){ System.out.print(count+" "); if(--count==0){ return; } } } publicstaticvoid main(String[] args){ Thread1 th1=new Thread1();//实例化继承了Thread的类 Thread1 th2=new Thread1(); th1.start();//调用start()方法, th2.start(); for(int i=0;i<1000;i++){ System.out.print("A "); } }

高中英语必修一第四单元重点难点

Unit four Earthquakes 1、In the city, the water pipes in some buildings crached and burst. 城市里,一些大楼里的水管爆裂。 burst爆裂,突发 用法归纳: The square is bursting with tourists. 广场上到处都是游客。 I felt as if my heart would burst with joy. 我觉得自己高兴得心花怒放。 The police burst through the door. 警察破门而入。 There was a burst of laughter in the next room. 隔壁房间里突然爆发出一阵笑声。 联想扩展: (1) burst in on…突然打断 He burst in on our conversation. 他突然打断了我们的谈话。 (2) burst into +n. 突然… The speaker burst into angry speech. 演讲者突然讲粗话。 (3) burst out + doing突然… The woman burst out crying like a child. 那个妇女突然像小孩一样哭了。 (4) burst to do sth. 迫切想做某事 I am bursting to tell you the news. 我迫不及待的想告诉你这个消息。 2、But the one million people of the city, who thought little of these events, were asleep as usual that night. 但是认为这没什么的一百万城里人,那天晚上还像往常一样睡觉。 易混辨析: affair, event, accident, incident, matter 和business 事;事情 affair 指要做的事或已经发生的事。多用复数。 event 指重大历史事件,也可指日常生活中较重要的事或比赛项目。 accident 指意外或偶然的不幸事件,多有不良后果。 incident 与重要事件有关的事情,尤指政治、军事上有争议的情况。 matter 需要认真考虑的事情。 business 日常事务、商业事务;还可以是公事。 3、The suffering of the people was extreme. 人们极度痛苦。 suffer 用法归纳: A, 受苦He suffered terribly when his mother died. B, 受到损失If I lost, my self-esteem will suffer. C, 遭受 He suffered no pain 联想扩展: suffer from 1、受…之苦I suffered most from lack of rest. 2、患…病I am suffering from a cold. 特别提示: suffer表示“患…病”时,后面一般跟疾病名称。 即时活用:

北师大版高中英语必修1-选修8重点短语汇总

北师大版高中英语必修1-选修8重点短语汇总 Unit 1 TV series 电视连续剧 talk show 谈话节目,现场访谈 couch potato 终日懒散在家的人 switch on 把开关打开,接通 switch off 把……关掉,关上 switch over 转换频道,转变 remote control 遥控 alarm clock 闹钟 go off (爆竹、铃等)响 take up 占据 be filled with 充满着 suffer from 忍受,遭受

distance learning 远程学习 at the moment 此刻,目前 over the years 数年间 kung fu (中国)功夫 Unit 2 manned spaceship 载人宇宙飞船 the United Nations 联合国 millions of 数百万 light bulb 电灯泡 in my opinion 在我看来 on one's own 单独地,独自地 give up 放弃 come to 达到某种状态 pull through 使从(受伤)中活下来,度过难关

commit suicide 自杀 get on 融洽相处;进展 get involved with 参加,参与 far too 太……,极为…… come off it 别胡扯 You've got a point here. 你所说的看来有道理。Unit 3 the Mid-Autumn Festival 中秋节 the Dragon Boat Festival 端午节 bean paste 豆馅 the Lantern Festival 元宵节 burn down 烧毁 sweet dumpling 元宵 lunar month 太阴月;阴历一个月

高一英语各单元知识点总结及重难点解析Unit21-22

高一英语各单元知识点总结及重难点解析Unit21-22 ☆重点句型☆ 1. It has been a long day. I can't keep my eyes open. 2. We can learn a lot about what a person is thinking by watching his or her body language. 3. In many countries, shaking one's head means "no" and nodding means "yes". 4. A way of raying "I am hungry" is patting the stomach before a meal. 5. Unlike traditional amusement parks, theme parks often want to teach visitors something. 6. What they all have in common is that they combine fun with the opportunity to learn ,something. 7. Visitors can go on exciting rides where they can feel what it is like to do the things they have seen their heroes do in the movie. 8. New theme parks are being built all over the world. ☆重点词汇☆ 1. unfair adj. 不公正的,不公平的 2. customer n. 顾客;主顾 3. avoid vt. 避免;消除 4. incredible adj. 难以置信的 5. manage vt. / vi. 做成(某事);管理;经营 6. fold vt. 折叠;合拢;抱住 7. crazy adj. 疯狂的;狂热的 8. firm adj. (指动作)稳定而有力的;牢固的 9. handshake n. 握手 10. bend vt. / vi. 弯曲;专心于;屈服 11. gently adv. 轻轻地;逐渐地 12. occur vi. 发生;出现 13. focus n. (兴趣活动等的)中心;焦点 14. specific adj. 具体的;特有的 15. amusement n. 消遣;娱乐(活动) 16. souvenir n. 纪念物;纪念品 17. attraction n. 吸引人的事物;吸引(力) 18. collection n. 收集;搜集;聚集 19. thrill n. 兴奋;激动;(使)激动;(使)胆战心惊 20. minority n. 少数民族;少数 21. educate vi. / vt. 教育;培养;训练 22. conservation n. (自然资源的)保护;管理;保存 23. divide vt. / vi.分;划分;分开;隔开 24. section n. 部分;区域 25. shuttle n. 往返汽车;航天飞机

java线程练习题及答案

线程与线程类 1 线程的概念 线程的概念来源于计算机的操作系统的进程的概念。进程是一个程序关于某个数据集的一次运行。也就是说,进程是运行中的程序,是程序的一次运行活动。 线程和进程的相似之处在于,线程和运行的程序都是单个顺序控制流。有些教材将线程称为轻量级进程(light weight process)。线程被看作是轻量级进程是因为它运行在一个程序的上下文内,并利用分配给程序的资源和环境。 作为单个顺序控制流,线程必须在运行的程序中得到自己运行的资源,如必须有自己的执行栈和程序计数器。线程内运行的代码只能在该上下文内。因此还有些教程将执行上下文(execution context)作为线程的同义词。 所有的程序员都熟悉顺序程序的编写,如我们编写的名称排序和求素数的程序就是顺序程序。顺序程序都有开始、执行序列和结束,在程序执行的任何时刻,只有一个执行点。线程(thread )则是进程中的一个单个的顺序控制流。单线程的概念很简单,如图1所示。 多线程(multi-thread )是指在单个的程序内可以同时运行多个不同的线程完成不同的任务,图2说明了一个程序中同时有两个线程运行。 图1 单线程程序示意图 图2 多线程程序示意图 有些程序中需要多个控制流并行执行。例如, for(int i = 0; i < 100; i++) System.out.println("Runner A = " + i); for(int j = 0; j < 100; j++ ) System.out.println("Runner B = "+j); 上面的代码段中,在只支持单线程的语言中,前一个循环不执行完不可能执行第二个循环。要使两个循环同时执行,需要编写多线程的程序。 很多应用程序是用多线程实现的,如Hot Java Web 浏览器就是多线程应用的例子。在Hot Java 浏览器中,你可以一边滚动屏幕,一边下载Applet 或图像,可以同时播放动画和声音等。 2 Thread 类和Runnable 接口 多线程是一个程序中可以有多段代码同时运行,那么这些代码写在哪里,如何创建线程对象呢? 首先,我们来看Java 语言实现多线程编程的类和接口。在https://www.doczj.com/doc/6c5938905.html,ng 包中定义了Runnable 接口和Thread 类。

高中英语语法知识点总结

高中英语语法知识点总结 一、定语从句与强调句陷阱题详解 1、The factory was built in a secret place, around _________ high mountains、 A、 which was B、 it was C、 which were D、 them were 【陷阱】 容易误选A或B,将 A、B中的 which 和 it 误认为是其后句子的主语。 【分析】 最佳答案是C,around which were high mountains 是一个由“介词+which”引出的非限制性定语从句,而在该从句中,主语是 high mountains,around which 是表语,所以句子谓语应用复数were,而不是用单数 was。请做以下类例题目(答案均为C):(1) Yesterday we visited a modern hospital, around _________ some fruit shops、 A、 which is B、 it is

C、 which are D、 them are(2) The murder happened in an old building, beside _________ the city police station、 A、 which are B、 it is C、 which is D、 them are(3) Next month we’ll move to a new building, next to _________ a nice restaurants where we can have Chinese food、 A、 which are B、 it is C、 which is D、 them are 2、 A man with a bleeding hand hurried in and asked, “Is there a hospital around _________ I can get some medicine for my wounded hand?” A、 that B、 which C、 where D、 what

高中英语语法重点难点回顾

高中英语语法重点难点回顾 主谓一致常考难题: 1. Five minutes is enough to do this exercise. Each boy and each girl wants to serve the people in future. More than one student has seen the film. Many a ship has been damaged in the storm. More members than one are against your plan. 一些有两个部分构成的名词表示衣物或工具作主语时, 谓语通常用复数形式:glasses, clothes, trousers, shoes, compasses, chopsticks, scissors等。 但如果主语用a kind of , a pair of , a series of等加名词构成时, 谓语动词一般用单数形式。A pair of shoes was on the desk. 并列主语如果指的是同一个人、同一事物或同一概念时, 谓语动词用单数形式, 这时and后面的名词没有冠词。例如: Truth and honesty is the best policy. The girl's teacher and friend is a young doctor. To love and to be loved is the great happiness. Going to bed early and getting up early is a good habit. A knife and fork is on the table. 当主语后面跟有as well as, as much as , no less than(不少于), along with(和···一起), with, like, rather than(宁愿·····而不是····), together with, but, except, besides, including, in addition to(除···还

Java第七单元练习题-Java多线程机制

7Java多线程机制 7.1单项选择题 1. 线程调用了sleep()方法后,该线程将进入()状态。 A. 可运行状态 B. 运行状态 C. 阻塞状态 D. 终止状态 2. 关于java线程,下面说法错误的是() A. 线程是以CPU为主体的行为 B. java利用线程使整个系统成为异步 C. 创建线程的方法有两种:实现Runnable接口和继承Thread类 D. 新线程一旦被创建,它将自动开始运行 3. 在java中的线程模型包含() A. 一个虚拟处理器 B. CPU执行的代码 C. 代码操作的数据 D. 以上都是 4.在java语言中,临界区可以是一个语句块,或者是一个方法,并用()关键字标识。 A. synchronized B. include C. import D. Thread 5. 线程控制方法中,yield()的作用是() A. 返回当前线程的引用 B. 使比其低的优先级线程执行 C. 强行终止线程 D. 只让给同优先级线程运行 6. 线程同步中,对象的锁在()情况下持有线程返回 A. 当synchronized()语句块执行完后 B. 当在synchronized()语句块执行中出现例外(exception)时 C. 当持有锁的线程调用该对象的wait()方法时 D. 以上都是 7. 在以下()情况下,线程就进入可运行状态 A. 线程调用了sleep()方法时 B. 线程调用了join()方法时

C. 线程调用了yield()方法时 D. 以上都是 8. java用()机制实现了进程之间的异步执行 A. 监视器 B. 虚拟机 C. 多个CPU D. 异步调用 类的方法中,toString()方法的作用是() A. 只返回线程的名称 B. 返回当前线程所属的线程组的名称 C. 返回当前线程对象 D. 返回线程的名称 语言具有许多优点和特点,下列选项中,哪个反映了Java程序并行机制的特点() A. 安全性 B. 多线程 C. 跨平台 D. 可移值 11.以下哪个关键字可以用来对对象加互斥锁?() A. transient B. synchronized C. serialize D. static 12.下面关于进程、线程的说法不正确的是( )。 A.进程是程序的一次动态执行过程。一个进程在其执行过程中,可以产生多个线程——多线程,形成多条执行线索。 B.线程是比进程更小的执行单位,是在一个进程中独立的控制流,即程序内部的控制流。线程本身不能自动运行,栖身于某个进程之中,由进程启动执行。 C.Java多线程的运行与平台无关。 D.对于单处理器系统,多个线程分时间片获取CPU或其他系统资源来运行。对于多处理器系统,线程可以分配到多个处理器中,从而真正的并发执行多任务。 7.2填空题 1.________是java程序的并发机制,它能同步共享数据、处理不同的事件。 2.线程是程序中的一个执行流,一个执行流是由CPU运行程序的代码、__________所形 成的,因此,线程被认为是以CPU为主体的行为。 3.线程的终止一般可以通过两种方法实现:自然撤销或者是__________. 4.线程模型在java中是由__________类进行定义和描述的。 5.线程的创建有两种方法:实现_________接口和继承Thread类。 6.多线程程序设计的含义是可以将程序任务分成几个________的子任务。 7.按照线程的模型,一个具体的线程也是由虚拟的CPU、代码与数据组成,其中代码与数 据构成了___________,线程的行为由它决定。 8.ava中,新建的线程调用start()方法、如(),将使线程的状态从New(新建状态)转换为 _________。 9.多线程是java程序的________机制,它能同步共享数据,处理不同事件。 10.进程是由代码、数据、内核状态和一组寄存器组成,而线程是表示程序运行状态的

java多线程实现调度

重庆交通大学综合性设计性实验报告 实验项目名称:进程调度(先来先服务) 实验项目性质: JAVA多线程 实验所属课程: JAVA程序设计 实验室(中心):语音大楼 8 楼 801 班级:软件专业 2012级2班 姓名:尚亚* 学号: 631206050216 指导教师:杨 实验完成时间: 2014 年 11 月 25 日

一、实验目的 1、理解程序、线程和进程的概念; 2、理解多线程的概念; 3、掌握线程的各种状态; 4、熟练使用Thread类创建线程; 5、熟练使用线程各种方法; 6、掌握线程的调度及线程同步的实现原理。 二、实验内容及要求 进程调度是处理机管理的核心内容。本实验要求采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法编写和调试一个简单的进程调度程序。通过本实验可以加深理解有关进程控制块、进程队列的概念。并体会了优先数和先来先服务调度算法的具体实施办法。 用JA V A语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。做一个能够直观体现多个进程时,CPU 是怎样调度就绪队列中的进程(按照先来先服务的原则)。

三、实验设备 PC机,windows7,eclipse。 四、设计方案 ㈠设计主要思想 (1)要模拟进程的调度算法,必须先体现处进程及系统资源。 (2)要体现先来先服务的算法,就必须表现出当有一个进程进入CPU时其他进程不能进入,并在就绪队列中排队。本实验建立了四个圆移动的线程表示作业调度,用圆在表示就绪队列的方框中停留表示进程在就绪队列中排队。 (3)当有一个圆移动到表示CPU的范围内时,让其它线程在就绪队列中排队,当CPU内无进程时,先来的圆先移动,以表示CPU 对进程的调度。 ㈡设计的主要步骤 (1)建立四个不同颜色的圆移动的线程,表示对四个进程的调度。 (2)当有一个表示进程的圆到达表示CPU范围内时,通过让其它几个圆停留在表示就绪队列的方框范围内,表示进程在就绪队列中排成队列。 (3)当第一个先到达的进程释放CPU,在排成队列的几个圆中选择先到达的圆,使其移动表示对先来的进程进行调度,直到所有的圆移动完毕。 五、主要代码 import java.awt.Font; import java.awt.event.*;

人教版英语必修一重难点解析2.4课

Section ⅣGrammar —直接引语与间接引语(Ⅱ)—祈使句 [新知导引] 1.(教材P12)“Look at this example,” the teacher said to us. →The teacher told_us_to_look at that example. 2.(教材P12)“Would you like to see my flat?” she asked. →She asked_me_to_see_her flat. 3.“Don't look out of the window, boys,” said the teacher. →The teacher told_the_boys_not_to_look out of the window. 4.He said, “How clever the child is!” →He said_how clever the child was. [语法详解] 1.祈使句的直接引语变间接引语,祈使句的间接引语形式多采用“动词+宾语+动词不定式”结构。常见的引述动词有ask, tell, beg, warn, remind, advise, order等。 引述表示警告或提醒的祈使句用remind, warn等词转述。 *“Take an umbrella in case of rain.”his mother said to him. →His mother reminded him to take an umbrella in case of rain. *The leader said to the workers, “Don't speak while working.” →The leader warned the workers not to speak while working. [名师点津] (1)无论是否定祈使句,还是表示委婉语气的否定疑问句,在变为间接引语时,要用不定式的否定形式: ①引述表示命令的祈使句,变间接引语时常采用ask/tell/order sb.(not) to do sth.的形式。 *“Finish the task in ten minutes.” the manager said to the clerk. →The manager told the clerk to finish the task in ten minutes. *“Keep silent!” the chairman said to the students. →The chairman ordered the students to keep silent. ②当直接引语为表示建议、提议、请求、劝告的祈使句(或表示请求、提议、劝告、建议的疑问句)时,多用suggest+doing/that从句(如suggest后接that从句时,从句使用虚拟语气should+动词原形,should也可省略),及ask/advise/want/beg sb.+to do等结构。 *Mary said, “Let's go to the art exhibition this afternoon.” →Mary suggested going to the art exhibition that afternoon. →Mary suggested that we (should)go to the art exhibition that afternoon.

高中英语语法知识点(可编辑修改word版)

高中英语知识点扫描大全最新 一、定语从句与强调句陷阱题详解 1.The factory was built in a secret place, around high mountains. A.which was B. it was C. which were D. them were 【陷阱】容易误选A 或B,将A、B 中的which 和it 误认为是其后句子的主语。 【分析】最佳答案是C,around which were high mountains 是一个由“介词+which”引出的非限制性定语从句,而在该从句中,主语是high mountains,around which 是表语,所以句子谓语应用复数were,而不是用单数was。请做以下类例题目(答案均为C): (1)Yesterday we visited a modern hospital, around some fruit shops. A.which is B. it is C. which are D. them are (2)The murder happened in an old building, beside the city police station. A.which are B. it is C. which is D. them are (3)Next month we’ll move to a new building, next to a nice restaurants where we can have Chinese food. A.which are B. it is C. which is D. them are 2.A man with a bleeding hand hurried in and asked, “Is there a hospital around I can get some medicine for my wounded hand?” A.that B. which C. where D. what 【陷阱】容易误选B,认为around 是介词,选which 用以代替前面的名词hospital,在此用作介词around 的宾语。 【分析】最佳答案为C。以上语法分析并不算错,但问题是,照此分析,此句的意思即为:有没有这样一个医院,我在它的附近可以买药治我的手伤?这样的语境显然有点不合情理,因为人们通常是在医院里面治伤,而不是在医院附近治伤。此题选C 的理由是:句中的around 不是介词,而是副词,意为“在附近”;其后的where 引导定语从句用以修饰其前的地点名词hospital,句意为:附近有没有一家医院,我可以去治我的手伤? 3.David is such a good boy all the teachers like. A. that B. who C. as D. whom 【陷阱】此题容易误选A,许多同学一看到题干中的such,再联系到选项中的that,便认为这是考查such … that …句式。况且,这样理解意思也还通顺。 【分析】最佳答案为C,不是A,因为在such … that … (如此……以至……)结构中,that 引导的是结果状语从句,并且that 在从句中不充当句子成分,若在上句填入such … that…,句末的动词like 缺宾语。选C 的理由如下:as 用作关系代词,用以引导定语从句,修饰其前的名词boy,同时as 在定语从句中用作动词like 的宾语,句意为“所有老师都喜欢的一位好男孩”。有的同学可能还会问,假若选A,能否将其后的that 视为引导定语从句的关系代词呢?不能,因为当先行词受到such 的修饰时,其后的定语从句应用关系代词as 来引导,而不用that。比较下面一题,答案为A,因为like 后有自己的宾语him:David is such a good boy all the teachers like him. A. that B. who C. as D. whom 请再做以下试题(答案选D): It was not such a good dinner she had promised us. A. like B. that C. which D. as 4.The buses, most of were already full, were surrounded by an angry crowd. A.that B. it C. them D. which 【陷阱】容易误选C,用them 代指the buses。 【分析】最佳答案是D。most of which were already full 为非限制性定语从句,修饰the buses。类似地,以下各题也选D: (1)His house, for (2)Ashdown forest, through he paid $10, 000, is now worth $50, 000. A. that B. it C. them D. which we’ll be driving, isn’t a forest any longer. A.that B. it C. them D. which

Java第七单元练习题Java多线程机制

J a v a第七单元练习题 J a v a多线程机制 The latest revision on November 22, 2020

7Java多线程机制 7.1单项选择题 1. 线程调用了sleep()方法后,该线程将进入()状态。 A. 可运行状态 B. 运行状态 C. 阻塞状态 D. 终止状态 2. 关于java线程,下面说法错误的是() A. 线程是以CPU为主体的行为 B. java利用线程使整个系统成为异步 C. 创建线程的方法有两种:实现Runnable接口和继承Thread类 D. 新线程一旦被创建,它将自动开始运行 3. 在java中的线程模型包含() A. 一个虚拟处理器 B. CPU执行的代码 C. 代码操作的数据 D. 以上都是 4.在java语言中,临界区可以是一个语句块,或者是一个方法,并用()关键字标识。 A. synchronized B. include C. import D. Thread 5. 线程控制方法中,yield()的作用是() A. 返回当前线程的引用 B. 使比其低的优先级线程执行 C. 强行终止线程 D. 只让给同优先级线程运行 6. 线程同步中,对象的锁在()情况下持有线程返回 A. 当synchronized()语句块执行完后 B. 当在synchronized()语句块执行中出现例外(exception)时 C. 当持有锁的线程调用该对象的wait()方法时 D. 以上都是 7. 在以下()情况下,线程就进入可运行状态 A. 线程调用了sleep()方法时 B. 线程调用了join()方法时 C. 线程调用了yield()方法时 D. 以上都是 8. java用()机制实现了进程之间的异步执行

人教版高中英语必修1重点和难点

Unit1 Friendship 重点短语: 1. Add up和 add up to的区别 2. Have got to= have to 3. Calm (sb.)down (sb.)使..镇定 4. Be concerned about= care about 5. Ignore= take no notice of 6. go through经历,经受 7. Walk the dog 8. A series of 一连串的,一系列的 9. at the point of就要…了 10. Take the final-term exam 11. hide away 12. To do with:与…有关 13. on purpose(to do) 14. Stay awake 15. in order to 16. At dusk 17. face to face 18. Happen to 19. hold/have sb. In one’s power 20. Not… any loger= no longer 21. Suffer from 22. Recover from 23. Draw the curtains 24. Have trouble/difficulty with sth 25. fall in love 26. Get along (well/badly/nicely) with sb 27.pack (sth.) up 28. Join in=take part in= participate in 29.ask sb. for advice 30. Make a list of 31. communicate with 重点句型 1. The reason for (doing) sth./why …is that…。。。的理由(原因)是。。。 friends are important to you.(列出为什么朋友对你很重要的原因清单) (Make a list of reasons why) 2. There is a time when…曾经有一段时间…. 3. It was the first time that…第一次做…(从句用完成时) It was the first time I could (这是我有生以来第一次面对面看Anne Hathaway) 4. Find it+形+to do sth. 发现做…很… 5. With+复合宾语(做条件,原因,方式和伴随等状语) Mother asked her whether/if she was tired . (妈妈问她手里拿这么多书累不累) (with so many books in her arms) 功能英语: Agreement:同意 I agree yes, I think so. So do I. Exactly. No problem. Sure Certainly Of course All right You’re right. Good idea I think that’s a good idea. Can’t agree more Disagreement:不同意 I don’t think so Neither do I. That’s not right. Yes,but…. I’m afraid not. I’m sorry, but I can’t agree. Unit 2 English around the world 重点短语: 1. More than:多于;不仅仅;不足以;很非常 2. Because of: 3. Native English speaker 4. Even if: 5. come up: 走进,上来,提出 6. In the early days

相关主题
文本预览
相关文档 最新文档