赞
踩
第一题:线程的基本概念、线程的基本状态及状态之间的关系?
线程,有时称为轻量级进程,是CPU使用的基本单元;它由线程ID、程序计数器、寄存器集合和堆栈组成。它与属于同一进程的其他线程共享其代码段、数据段和其他操作系统资源(如打开文件和信号)。
线程有四种状态:新生状态、可运行状态、被阻塞状态、死亡状态。状态之间的转换如下图所示:
第二题:线程与进程的区别?
1、 线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程。
2、 一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。
3、 系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。那就是说,出了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
4、 与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少多了。
5、 进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。
第三题:多线程有几种实现方法,都是什么?
1. 继承 Thread 类
2. 实现 Runnable 接口再 new Thread(YourRunnableOjbect)
第四题:多线程同步和互斥有几种实现方法,都是什么?
线程间的同步方法大体可分为两类:用户模式和内核模式。顾名思义,内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作。
用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。内核模式下的方法有:事件,信号量,互斥量。
第五题:多线程同步和互斥有何异同,在什么情况下分别使用他们?举例说明。
线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步(下文统称为同步)。
1
2、以下多线程对int型变量x的操作,哪几个不需要进行同步(D)
A. x=y; B. x++; C. ++x; D. x=1;
详见:后面系列解析
3、多线程中栈与堆是公有的还是私有的 (C)
A:栈公有, 堆私有
B:栈公有,堆公有
C:栈私有, 堆公有
D:栈私有,堆私有
4、临界区(Critical Section)和互斥量(Mutex)
两者都可以用于同一进程中不同子线程对资源的互斥访问。
互斥量是内核对象,因此还可以用于不同进程中子线程对资源的互斥访问。
互斥量可以很好的解决由于线程意外终止资源无法释放的问题。
5、一个全局变量tally,两个线程并发执行(代码段都是ThreadProc),问两个线程都结束后,tally取值范围。
inttally = 0;//glable
voidThreadProc()
{
for(inti = 1;i <= 50;i++)
tally += 1;
}
答:[50,100]
6、编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。
思路:用信号量进行各个子线程之间的互斥,创建3个信号量A、B、C。初始时A的资源数为1,B、C的资源数为0,访问A之后,将B的资源数加1,访问B之后将C的资源数加1,访问C之后将A的资源数加1。创建3个子线程顺序访问资源A、B、C。
- #include "stdafx.h"
- #include "stdio.h"
- #include "stdlib.h"
- #include <iostream>
- #include <string>
- #include <stack>
- #include <windows.h>
- #include <process.h>
- using namespace std;
-
- const int THREAD_NUM = 10;
- HANDLE ga,gb,gc;
-
- unsigned int __stdcall FunA(void *pPM)
- {
- Sleep(50);//some work should to do
- printf("A\n");
- ReleaseSemaphore(gb, 1, NULL);//递增信号量B的资源数
-
- return 0;
- }
-
- unsigned int __stdcall FunB(void *pPM)
- {
- Sleep(50);//some work should to do
- printf("B\n");
- ReleaseSemaphore(gc, 1, NULL);//递增信号量C的资源数
-
- return 0;
- }
-
- unsigned int __stdcall FunC(void *pPM)
- {
- Sleep(50);//some work should to do
- printf("C\n");
- ReleaseSemaphore(ga, 1, NULL);//递增信号量A的资源数
-
- return 0;
- }
-
- int main()
- {
- //初始化信号量
- ga = CreateSemaphore(NULL, 1, 1, NULL);//当前1个资源,最大允许1个同时访问
- gb = CreateSemaphore(NULL, 0, 1, NULL);//当前0个资源,最大允许1个同时访问
- gc = CreateSemaphore(NULL, 0, 1, NULL);//当前0个资源,最大允许1个同时访问
-
- HANDLE handle[THREAD_NUM];
- int i = 0;
- while (i < THREAD_NUM)
- {
- WaitForSingleObject(ga, INFINITE); //等待信号量A>0
- handle[i] = (HANDLE)_beginthreadex(NULL, 0, FunA, &i, 0, NULL);
- WaitForSingleObject(gb, INFINITE); //等待信号量B>0
- handle[i] = (HANDLE)_beginthreadex(NULL, 0, FunB, &i, 0, NULL);
- WaitForSingleObject(gc, INFINITE); //等待信号量C>0
- handle[i] = (HANDLE)_beginthreadex(NULL, 0, FunC, &i, 0, NULL);
-
- ++i;
- }
- WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);
-
- //销毁信号量
- CloseHandle(ga);
- CloseHandle(gb);
- CloseHandle(gc);
- for (i = 0; i < THREAD_NUM; i++)
- CloseHandle(handle[i]);
- return 0;
- }
7、生产者消费者问题:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,所有生产者和消费者都是异步方式运行的,但它们必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经装满产品且尚未被取走的缓冲区中投放产品。
分析:假设1个生产者,2个消费者,缓冲区大小为4。
第一.从缓冲区取出产品和向缓冲区投放产品必须是互斥进行的。可以用关键段和互斥量来完成。
第二.生产者要等待缓冲区为空,这样才可以投放产品,消费者要等待缓冲区不为空,这样才可以取出产品进行消费。并且由于有二个等待过程,所以要用二个事件或信号量来控制。
代码如下:
- //1生产者 2消费者 4缓冲区
- #include "stdafx.h"
- #include "stdio.h"
- #include "stdlib.h"
- #include <iostream>
- #include <string>
- #include <stack>
- #include <windows.h>
- #include <process.h>
- using namespace std;
-
- //设置控制台输出颜色
- BOOL SetConsoleColor(WORD wAttributes)
- {
- HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
- if (hConsole == INVALID_HANDLE_VALUE)
- return FALSE;
-
- return SetConsoleTextAttribute(hConsole, wAttributes);
- }
-
- const int END_PRODUCE_NUMBER = 8; //生产产品个数
- const int BUFFER_SIZE = 4; //缓冲区个数
- int g_Buffer[BUFFER_SIZE]; //缓冲池
- int g_i, g_j;
- CRITICAL_SECTION g_cs; //信号量与关键段
- HANDLE g_hSemaphoreBufferEmpty, g_hSemaphoreBufferFull;
-
- //生产者线程函数
- unsigned int __stdcall ProducerThreadFun(PVOID pM)
- {
- for (int i = 1; i <= END_PRODUCE_NUMBER; i++)
- {
- //等待有空的缓冲区出现
- WaitForSingleObject(g_hSemaphoreBufferEmpty, INFINITE);
-
- //互斥的访问缓冲区
- EnterCriticalSection(&g_cs);
- g_Buffer[g_i] = i;
- printf("生产者在缓冲池第%d个缓冲区中投放数据%d\n", g_i, g_Buffer[g_i]);
- g_i = (g_i + 1) % BUFFER_SIZE;
- LeaveCriticalSection(&g_cs);
-
- //通知消费者有新数据了
- ReleaseSemaphore(g_hSemaphoreBufferFull, 1, NULL);
- }
- printf("生产者完成任务,线程结束运行\n");
- return 0;
- }
-
- //消费者线程函数
- unsigned int __stdcall ConsumerThreadFun(PVOID pM)
- {
- while (true)
- {
- //等待非空的缓冲区出现
- WaitForSingleObject(g_hSemaphoreBufferFull, INFINITE);
-
- //互斥的访问缓冲区
- EnterCriticalSection(&g_cs);
- SetConsoleColor(FOREGROUND_GREEN);
- printf(" 编号为%d的消费者从缓冲池中第%d个缓冲区取出数据%d\n", GetCurrentThreadId(), g_j, g_Buffer[g_j]);
- SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
- if (g_Buffer[g_j] == END_PRODUCE_NUMBER)//结束标志
- {
- LeaveCriticalSection(&g_cs);
- //通知其它消费者有新数据了(结束标志)
- ReleaseSemaphore(g_hSemaphoreBufferFull, 1, NULL);
- break;
- }
- g_j = (g_j + 1) % BUFFER_SIZE;
- LeaveCriticalSection(&g_cs);
-
- Sleep(50); //some other work to do
-
- ReleaseSemaphore(g_hSemaphoreBufferEmpty, 1, NULL);
- }
- SetConsoleColor(FOREGROUND_GREEN);
- printf(" 编号为%d的消费者收到通知,线程结束运行\n", GetCurrentThreadId());
- SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
- return 0;
- }
-
- int main()
- {
- InitializeCriticalSection(&g_cs);
- //初始化信号量,一个记录有产品的缓冲区个数,另一个记录空缓冲区个数.
- g_hSemaphoreBufferEmpty = CreateSemaphore(NULL, 4, 4, NULL);
- g_hSemaphoreBufferFull = CreateSemaphore(NULL, 0, 4, NULL);
- g_i = 0;
- g_j = 0;
- memset(g_Buffer, 0, sizeof(g_Buffer));
-
- const int THREADNUM = 3;
- HANDLE hThread[THREADNUM];
- //生产者线程
- hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ProducerThreadFun, NULL, 0, NULL);
- //消费者线程
- hThread[1] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFun, NULL, 0, NULL);
- hThread[2] = (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFun, NULL, 0, NULL);
- WaitForMultipleObjects(THREADNUM, hThread, TRUE, INFINITE);
-
- for (int i = 0; i < THREADNUM; i++)
- CloseHandle(hThread[i]);
-
- //销毁信号量和关键段
- CloseHandle(g_hSemaphoreBufferEmpty);
- CloseHandle(g_hSemaphoreBufferFull);
- DeleteCriticalSection(&g_cs);
- return 0;
- }
8、读者写者问题:这也是一个非常经典的多线程题目,题目大意如下:有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写。
分析:首先来找找哪些是属于“等待”情况。
第一、写者要等到没有读者时才能去写文件。
第二、所有读者要等待写者完成写文件后才能去读文件。
找完“等待”情况后,再看看有没有要互斥访问的资源。由于只有一个写者而读者们是可以共享的读文件,所以按题目要求并没有需要互斥访问的资源。代码如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。