什么是进程?什么是线程?总结

1.什么是进程?什么是线程?

进程是表示资源分配的基本单位,又是调度运行的基本单位。例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,包括各种表格、内存空间、磁盘空间、I/O设备等。然后,把该进程放人进程的就绪队列。进程调度程序选中它,为它分配CPU以及其它有关资源,该进程才真正运行。所以,进程是系统中的并发执行的单位。
MacWindows NT等采用微内核结构的操作系统中,进程的功能发生了变化:它只是资源分配的单位,而不再是调度运行的单位。在微内核系统中,真正调度运行的基本单位是线程。因此,实现并发功能的单位是线程。
线程概念
  线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。如果把进程理解为在逻辑上操作系统所完成的任务,那么线程表示完成该任务的许多可能的子任务之一。例如,假设用户启动了一个窗口中的数据库应用程序,操作系统就将对数据库的调用表示为一个进程。假设用户要从数据库中产生一份工资单报表,并传到一个文件中,这是一个子任务;在产生工资单报表的过程中,用户又可以输人数据库查询请求,这又是一个子任务。这样,操作系统则把每一个请求――工资单报表和新输人的数据查询表示为数据库进程中的独立的线程。线程可以在处理器上独立调度执行,这样,在多处理器环境下就允许几个线程各自在单独处理器上进行。操作系统提供线程就是为了方便而有效地实现这种并发性。

 举个例子来说多线程就像是火车上的每节车厢,而进程就是火车。

2.多进程和多线程的区别?

我们从各个方面来看待这个问题,由下面的图片说明:

对比维度

多进程

多线程

总结

数据共享、同步

数据共享复杂,需要用IPC;数据是分开的,同步简单

因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂

各有优势

内存、CPU

占用内存多,切换复杂,CPU利用率低

占用内存少,切换简单,CPU利用率高

线程占优

创建销毁、切换

创建销毁、切换复杂,速度慢

创建销毁、切换简单,速度很快

线程占优

编程、调试

编程简单,调试简单

编程复杂,调试复杂

进程占优

可靠性

进程间不会互相影响

一个线程挂掉将导致整个进程挂掉

进程占优

分布式

适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单

适应于多核分布式

进程占优

3.进程之间的通信方式以及优缺点?

1)管道
管道分为有名管道和无名管道
无名管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系一般指的是父子关系。无明管道一般用于两个不同进程之间的通信。当一个进程创建了一个管道,并调用fork创建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端,这样提供了两个进程之间数据流动的一种方式。
有名管道也是一种半双工的通信方式,但是它允许无亲缘关系进程间的通信。

无名管道:优点:简单方便;缺点:1)局限于单向通信2)只能创建在它的进程以及其有亲缘关系的进程之间;3)缓冲区有限;
有名管道:优点:可以实现任意关系的进程间的通信;缺点:1)长期存于系统中,使用不当容易出错;2)缓冲区有限
2)信号量
信号量是一个计数器,可以用来控制多个线程对共享资源的访问.,它不是用于交换大批数据,而用于多线程之间的同步.它常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源.因此,主要作为进程间以及同一个进程内不同线程之间的同步手段.
优点:可以同步进程;缺点:信号量有限

3)信号
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生.

4)
消息队列
消息队列是消息的链表,存放在内核中并由消息队列标识符标识.消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等特点.消息队列是UNIX下不同进程之间可实现共享资源的一种机制,UNIX允许不同进程将格式化的数据流以消息队列形式发送给任意进程.对消息队列具有操作权限的进程都可以使用msget完成对消息队列的操作控制.通过使用消息类型,进程可以按任何顺序读信息,或为消息安排优先级顺序.

优点:可以实现任意进程间的通信,并通过系统调用函数来实现消息发送和接收之间的同步,无需考虑同步问题,方便;缺点:信息的复制需要额外消耗CPU的时间,不适宜于信息量大或操作频繁的场合

5)共享内存
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问.共享内存是最快的IPC(进程间通信)方式,它是针对其它进程间通信方式运行效率低而专门设计的.它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步与通信.

优点:无须复制,快捷,信息量大;缺点:1)通信是通过将共无法实现享空间缓冲区直接附加到进程的虚拟地址空间中来实现的,因此进程间的读写操作的同步问题;2)利用内存缓冲区直接交换信息,内存的实体存在于计算机中,只能同一个计算机系统中的诸多进程共享,不方便网络通信

6)套接字:可用于不同及其间的进程通信
优点:1)传输数据为字节级,传输数据可自定义,数据量小效率高;2)传输数据时间短,性能高;3) 适合于客户端和服务器端之间信息实时交互;4) 可以加密,数据安全性强
缺点:1) 需对传输的数据进行解析,转化成应用级的数据。

4.线程之间的通信方式?

 # 锁机制:包括互斥锁、条件变量、读写锁
   *互斥锁提供了以排他方式防止数据结构被并发修改的方法。
   *读写锁允许多个线程同时读共享数据,而对写操作是互斥的。
   *条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
信号机制(Signal):类似进程间的信号处理
    线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。

5.什么时候用多线程?什么时候用多进程?

1)需要频繁创建销毁的优先用线程
原因请看上面的对比。
这种原则最常见的应用就是Web服务器了,来一个连接建立一个线程,断了就销毁线程,要是用进程,创建和销毁的代价是很难承受的
2)需要进行大量计算的优先使用线程
所谓大量计算,当然就是要耗费很多CPU,切换频繁了,这种情况下线程是最合适的。
这种原则最常见的是图像处理、算法处理。
3)强相关的处理用线程,弱相关的处理用进程
什么叫强相关、弱相关?理论上很难定义,给个简单的例子就明白了。
一般的Server需要完成如下任务:消息收发、消息处理。消息收发消息处理就是弱相关的任务,而消息处理里面可能又分为消息解码业务处理,这两个任务相对来说相关性就要强多了。因此消息收发消息处理可以分进程设计,消息解码业务处理可以分线程设计。
当然这种划分方式不是一成不变的,也可以根据实际情况进行调整。
4)可能要扩展到多机分布的用进程,多核分布的用线程
原因请看上面对比。
5)都满足需求的情况下,用你最熟悉、最拿手的方式
至于数据共享、同步编程、调试可靠性这几个维度的所谓的复杂、简单应该怎么取舍,我只能说:没有明确的选择方法。但我可以告诉你一个选择原则:如果多进程和多线程都能够满足要求,那么选择你最熟悉、最拿手的那个。

1、线程的基本概念、线程的基本状态与状态之间的关系?

线程是进程里面一个执行上下文,或者是执行序列。线程是进程级别上的多道编程。同一进程的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈。线程之间切换快,无需陷入内核态。

线程状态

 

阻塞状态分分为三种:等待阻塞(wait)、同步阻塞( 加锁 )、其他阻塞(睡眠)

新建状态

当用new操作符创建一个线程时。此时程序还没有开始运行线程中的代码。

就绪状态

一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序来调度的。

运行状态(runing

当线程获得 CPU时间后,它才进图运行状态,真正开始执行run()方法。

阻塞状态(blocked

线程运行过程中,可能由于各种原因进入阻塞状态:

线程通过调用sleep方法进入睡眠状态;

线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;

线程试图得到一个锁,而该锁正被其他线程持有;

线程在等待某个触发条件;

所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。

死亡状态(dead

有两个原因会导致线程死亡:

run方法正常退出而自然死亡;

一个未捕获的异常终止了run方法而使线程猝死;

为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法,如果是可运行或被阻塞,这个方法返回true;如果线程仍旧是new状态且不是可运行的,或者线程死亡了,则返回false

2、进程与线程的区别:

一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。用户根据需要在应用程序中创建其他线程,多个线程并发地运行在同一个进程。一个进程汇总的所有线程都在该进程的虚拟地址空间汇总,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。

基于进程的多任务处理是程序的并发执行。基于线程的多任务处理是同一程序的片段的并发执行;

地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间;

资源拥有:同一进程内的线程共享本进程的资源如内存、I/Ocpu等,但是进程之间的资源是独立的;

一个进程奔溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃则整个进程都死掉,所以多进程要比多线程健壮;

进程切换时,消耗资源大,效率高,所以涉及到频繁切换时,使用线程要好于进程;

执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存于应用程序中,有应用程序提供多个线程执行控制。

线程是处理器调度的基本单位,但进程不是。

3、多线程有几种实现方法

C++创建多线程的三种方式:

1.CreateThread()

CreateThread()windowsAPI函数,提供操作系统级别的创建线程的操作,且仅限于工作者线程。不调用MFCRTL函数(标准C语言函数),即只调用win32API时,可以 CreateThread。在使用过程中要考虑到进程捡的同步与互斥关系(防止死锁)。

线程函数定义为: DWORD WINAPI _yourThreradFun(LPVOID)

头文件 <windows.h>

创建线程API

 

  1.  1 HANDLE CreateThread(
  2.  2     __in   SEC_ATTRS
  3.  3     SecurityAttributes,    //线程安全属性
  4.  4     __in   ULONG
  5.  5     StackSize,        // 堆栈大小
  6.  6     __in   SEC_THREAD_START
  7.  7     StartFunction,    // 线程函数
  8.  8     __in   PVOID
  9.  9     ThreadParameter,  // 线程参数
  10. 10     __in   ULONG
  11. 11     CreationFlags,    // 线程创建属性
  12. 12     __out  PULONG
  13. 13     ThreadId          // 线程ID
  14. 14     );

使用步骤:

  1. HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);
  2. CloseHandle(hThread);

2、互斥API:互斥量实现

 

  1.  1 HANDLE CreateMutex(
  2.  2     LPSECURITY_ATTRIBUTES lpMutexAttributes,
  3.  3     BOOL bInitialOwner,                       // 指定该资源初始是否归属创建它的进程
  4.  4     LPCTSTR lpName                            // 指定资源的名称     
  5.  5     );
  6.  6
  7.  7 BOOL ReleaseMutex(
  8.  8     HANDLE hMutex   // 该函数用于释放一个独占资源,进程一旦释放该资源,该资源就不再属于它了
  9.  9     );
  10. 10
  11. 11 DWORD WaitForSingleObject(
  12. 12     HANDLE hHandle,        // 指定所申请的资源的句柄
  13. 13     DWORD dwMilliseconds   // 一般指定为INFINITE,表示如果没有申请到资源就一直等待该资源
  14. 14     );

3、互斥API:临界区实现

  1. 1 CRITICAL_SECTION cs;
  2. 2 InitializeCriticalSection(&cs);
  3. 3 EnterCriticalSection(&cs);
  4. 4 LeaveCriticalSection(&cs);
  5. 5 DeleteCriticalSection(&cs);
  6.  

例子:

 

  1.  #include <iostream>  
  2.  #include <windows.h>  
  3.  using namespace std;
  4.  
  5.  HANDLE hMutex;
  6.  
  7.  DWORD WINAPI Fun(LPVOID lpParamter)
  8.  {
  9.      while (1) {
  10.          WaitForSingleObject(hMutex, INFINITE);
  11.          cout << "Fun display!" << endl;
  12.          Sleep(1000);
  13.          ReleaseMutex(hMutex);
  14.      }
  15.  }
  16.  
  17.  int main()
  18.  {
  19.      HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NUL
  20.      hMutex = CreateMutex(NULL, FALSE, "screen");
  21.      CloseHandle(hThread);
  22.      while (1) {
  23.          WaitForSingleObject(hMutex, INFINITE);
  24.          cout << "main display!" << endl;
  25.          Sleep(2000);
  26.          ReleaseMutex(hMutex);
  27.      }
  28.  
  29.      return 0;
  30.  }
  31.  

 

4、多线程同步和互斥实现方式

当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源。例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件中的字符数。当然,在把整个文件调入内存之前,统计它的计数是没有意义的。但是,由于每个操作都有自己的线程,操作系统会把两个线程当作是互不相干的任务分别执行,这样就可能在没有把整个文件装入内存时统计字数。为解决此问题,你必须使两个线程同步工作。

所谓同步,是指在不同进程之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。如果用对资源的访问来定义的话,同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

所谓互斥,是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。如果用对资源的访问来定义的话,互斥某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

实现方式:

线程间的同步方法大体可分为两类:用户模式和内核模式。内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作。

用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。

内核模式下的方法有:事件,信号量,互斥量。

1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问(可能造成竞争的共享资源) 
2
、互斥量:为协调共同对一个共享资源的单独访问而设计的。 
3
、信号量:为控制一个具有有限数量用户资源而设计。 
4
、事 :用来通知线程有一些事件已发生,从而启动后继任务的开始。

同步的目的:多线程程序 的执行结果有可能是不确定的---》为了消除不确定,产生了线程同步,即就是不管线程之间的执行如何穿梭,其运行结果都是正确的。

5、多线程同步和互斥有何异同,在什么情况下分别使用它们?

线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。

线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步(下文统称为同步)。

线程同步解决多线程并发问题:

 

几种内核对象中,除了互斥量,没有任何一个会记住自己是哪个线程等待成功的。

互斥量和关键段的比较:

1)关键段只适用于同一个进程,互斥量可适用与不同的进程

2)关键段的效率更高

3)关键段不安全,而互斥量更安全;

假如把整条道路看成是一个【进程】的话,那么马路中间白色虚线分隔开来的各个车道就是进程中的各个【线程】了。
  这些线程(车道)共享了进程(道路)的公共资源(土地资源)
  这些线程(车道)必须依赖于进程(道路),也就是说,线程不能脱离于进程而存在(就像离开了道路,车道也就没有意义了)
  这些线程(车道)之间可以并发执行(各个车道你走你的,我走我的),也可以互相同步(某些车道在交通灯亮时禁止继续前行或转弯,必须等待其它车道的车辆通行完毕)
  这些线程(车道)之间依靠代码逻辑(交通灯)来控制运行,一旦代码逻辑控制有误(死锁,多个线程同时竞争唯一资源),那么线程将陷入混乱,无序之中。
  这些线程(车道)之间谁先运行是未知的,只有在线程刚好被分配到CPU时间片(交通灯变化)的那一刻才能知道。
  注:
  由于用于互斥的信号量sem与所有的并发进程有关,所以称之为公有信号量。公有信号量的值反映了公有资源的数量。只要把临界区置于P(sem)V(sem)之间,即可实现进程间的互斥。就象火车中的每节车厢只有一个卫生间,该车厢的所有旅客共享这个公有资源:卫生间,所以旅客间必须互斥进入卫生间,只要把卫生间放在P(sem)V(sem)之间,就可以到达互斥的效果。

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

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

   一。概念性问答题

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

概念:线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

    好处 

1)易于调度。

               2)提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。

               3)开销少。创建线程比创建进程要快,所需开销很少。。

               4)利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。

状态:运行、阻塞、挂起阻塞、就绪、挂起就绪

    状态之间的转换:准备就绪的进程,被CPU调度执行,变成运行态;

                                 运行中的进程,进行I/O请求或者不能得到所请求的资源,变成阻塞态;

                                 运行中的进程,进程执行完毕(或时间片已到),变成就绪态;

                                 将阻塞态的进程挂起,变成挂起阻塞态,当导致进程阻塞的I/O操作在用户重启进程前完成(称之为唤醒),挂起阻塞态变成挂起就绪态,当用户在I/O操作结束之前重启进程,挂起阻塞态变成阻塞态;

                                 将就绪(或运行)中的进程挂起,变成挂起就绪态,当该进程恢复之后,挂起就绪态变成就绪态;                

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

   这个题目问到的概率相当大,计算机专业考研中也常常考到。要想全部答出比较难。

进程和线程的关系:

    1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

    2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。

    3)处理机分给线程,即真正在处理机上运行的是线程。

    4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。线程是指进程内的一个执行单元,也是进程内的可调度实体.

进程与线程的区别:

    1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位

    2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行

    3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.

    4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。

   第三题:多线程有几种实现方法,都是什么?

C++中多线程实现方法:

windows下通过api CreateThreadlinux下则常用pthread库,这些都是最底层的实现,最新的C++11标准里增加了std::thread多线程库,使用第三方库的话就更多了,比如boostthread等等,不推荐使用vc自家的_beginthread,尤其有跨平台需求的时候。

JAVA中实现多线程的方法:

 1. 继承 Thread 
    2. 实现 Runnable 接口再 new Thread(YourRunnableOjbect) 推荐
 

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

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

   线程间的同步方法大体可分为两类:用户模式和内核模式。顾名思义,内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作。
用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。内核模式下的方法有:事件,信号量,互斥量。

 

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

当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源。例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件中的字符数。当然,在把整个文件调入内存之前,统计它的计数是没有意义的。但是,由于每个操作都有自己的线程,操作系统会把两个线程当作是互不相干的任务分别执行,这样就可能在没有把整个文件装入内存时统计字数。为解决此问题,你必须使两个线程同步工作。

      所谓同步,是指散步在不同进程之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。如果用对资源的访问来定义的话,同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

        所谓互斥,是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。如果用对资源的访问来定义的话,互斥某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

     第六题:进程间通信的方式?

    1)管道(pipe)及有名管道(named pipe):管道可用于具有亲缘关系的父子进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。

    2)信号(signal):信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致的。

    3)消息队列(message queue):消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息。

    4)共享内存(shared memory):可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。

    5)信号量(semaphore):主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段。

    6)套接字(socket):这是一种更为一般得进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。

二。选择题

   第一题(百度笔试题):

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

    A.x=y;      B. x++;    C.++x;    D. x=1;

  答案参见:http://blog.csdn.net/jjj19891128/article/details/24392229
 

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

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

    A:栈公有, 堆私有

    B:栈公有,堆公有

    C:栈私有, 堆公有D:栈私有,堆私有

一般来说栈是私有的

堆是共有的

但是你可以为特定的线程创建私有的堆

堆和栈的区别如下:

 

堆很灵活,但是不安全。对于对象,我们要动态地创建、销毁,不能说后创建的对象没有销毁,先前创建的对象就不能销毁,那样的话我们的程序就寸步难行,所以Java中用堆来存储对象。而一旦堆中的对象被销毁,我们继续引用这个对象的话,就会出现著名的 NullPointerException,这就是堆的缺点——错误的引用逻辑只有在运行时才会被发现。

 

栈不灵活,但是很严格,是安全的,易于管理。因为只要上面的引用没有销毁,下面引用就一定还在,所以,在栈中,上面引用永远可以通过下面引用来查找对象,同时如果确认某一区间的内容会一起存在、一起销毁,也可以上下互相引用。在大部分程序中,都是先定义的变量、引用先进栈,后定义的后进栈,同时,区块内部的变量、引用在进入区块时压栈,区块结束时出栈,理解了这种机制,我们就可以很方便地理解各种编程语言的作用域的概念了,同时这也是栈的优点——错误的引用逻辑在编译时就可以被发现。

 

总之,就是变量和对象的引用存储在栈区中,而对象在存储在堆中


 

三。综合题

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

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

        两者都可以用于同一进程中不同子线程对资源的互斥访问。

        互斥量是内核对象,因此还可以用于不同进程中子线程对资源的互斥访问。

        互斥量可以很好的解决由于线程意外终止资源无法释放的问题。

    第二题:

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

    inttally = 0;//glable

    voidThreadProc()

    {

    forint i = 1; i <= 50;i++

    tally += 1;

    }

 答:[50,100]
 

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

   子线程循环 10次,接着主线程循环 100次,接着又回到子线程循环 10次,接着再回到主线程又循环 100次,如此循环50次,试写出代码。

   第四题(迅雷笔试题):

   编写一个程序,开启3个线程,这3个线程的ID分别为ABC,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC依次递推。

   第五题(Google面试题)

   有四个线程1234.线程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

   请设计程序。

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

   第六题

   生产者消费者问题

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

   第七题

   读者写者问题

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

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值