一.概念性问答题
第一题:线程的基本概念、线程的基本状态及状态之间的关系?
线程:一个线程是进程的一个顺序执行流。同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈。线程在切换时负荷小,因此,线程也被称为轻负荷进程。一个进程中可以包含多个线程。
多个线程或进程”同时”运行只是我们感官上的一种表现。事实上进程和线程是并发运行的,OS的线程调度机制将时间划分为很多时间片段(时间片),尽可能均匀分配给正在运行的程序,获取CPU时间片的线程或进程得以被执行,其他则等待。而CPU则在这些进程或线程上来回切换运行。微观上所有进程和线程是走走停停的,宏观上都在运行,这种都运行的现象叫并发,但是不是绝对意义上的“同时发生。
线程状态
线程有四种状态:新生状态、可运行状态、被阻塞状态、死亡状态。状态之间的转换如下图所示:
第二题:线程与进程的区别?
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
2) 线程的划分尺度小于进程,使得多线程程序的并发性高。
3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
第三题:多线程有几种实现方法,都是什么?
第四题:多线程同步和互斥有几种实现方法,都是什么?
临界区(Critical Section)(同一个进程内,实现互斥)
保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。
互斥量(Mutex)(可以跨进程,实现互斥)
互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。互斥量比临界区复杂。因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。
互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,所以如果只为了在进程内部是用的话使用临界区会带来速度上的优势并能够减少资源占用量。
信号量(Semaphores)(主要是实现同步,可以跨进程)
信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。它指出了同时访问共享资源的线程最大数目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就会减1,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目,不能在允许其他线程的进入,此时的信号量信号将无法发出
事件(Event)(实现同步,可以跨进程)
事件对象也可以通过通知操作的方式来保持线程的同步。并且可以实现不同进程中的线程同步操作。
第五题:多线程同步和互斥有何异同,在什么情况下分别使用他们?举例说明。
线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步
二.题目
第一题 以下多线程对int型变量x的操作,哪几个不需要进行同步: D
A. x=y; B. x++; C. ++x; D. x=1;
解释:
x = y;
mov eax,dword ptr [y]
mov dword ptr [x],eax
x++;
mov eax,dword ptr [x]
add eax,1
mov dword ptr [x],eax
++x;
mov eax,dword ptr [x]
add eax,1
mov dword ptr [x],eax
x = 1;
mov dword ptr [x],1
第四题(迅雷笔试题):
编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。
利用互斥锁和3个条件变量来控制3个线程的顺序
1 include <unistd.h> 2 #include <pthread.h> 3 #include <ostream> 4 #include <iostream> 5 6 using namespace std ; 7 8 void* routine1(void* p) ; 9 void* routine2(void* p) ; 10 void* routine3(void* p) ; 11 12 int flag = 1 ; 13 14 pthread_mutex_t mux ; 15 //static pthread_mutexattr_t muxattr = PTHREAD_MUTEX_TIMED_NP ; 16 static pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER ; 17 static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER ; 18 static pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER ; 19 20 int main(int argc, char* argv[]) 21 { 22 pthread_t id1, id2, id3 ; 23 pthread_attr_t attr1, attr2, attr3 ; 24 25 pthread_cond_init(&cond1, NULL) ; 26 pthread_cond_init(&cond2, NULL) ; 27 pthread_cond_init(&cond3, NULL) ; 28 29 pthread_mutex_init(&mux, 0) ; 30 31 pthread_attr_init(&attr1) ; 32 pthread_attr_init(&attr2) ; 33 pthread_attr_init(&attr3) ; 34 35 pthread_attr_setdetachstate(&attr1, PTHREAD_CREATE_JOINABLE) ; 36 pthread_attr_setdetachstate(&attr2, PTHREAD_CREATE_JOINABLE) ; 37 pthread_attr_setdetachstate(&attr3, PTHREAD_CREATE_JOINABLE) ; 38 39 pthread_attr_setstacksize(&attr1, 1024*100) ; 40 pthread_attr_setstacksize(&attr2, 1024*100) ; 41 pthread_attr_setstacksize(&attr3, 1024*100) ; 42 43 pthread_create(&id1, &attr1, routine1, (void*)NULL) ; 44 pthread_create(&id2, &attr2, routine2, (void*)NULL) ; 45 pthread_create(&id3, &attr3, routine3, (void*)NULL) ; 46 47 sleep(1) ; 48 pthread_cond_signal(&cond1) ; 49 50 pthread_join(id1, NULL) ; 51 pthread_join(id2, NULL) ; 52 pthread_join(id3, NULL) ; 53 54 cout << "END " ; 55 56 return 0 ; 57 } 58 59 void* routine1(void* p) 60 { 61 for(int i=0; i<10; i++) 62 { 63 pthread_mutex_lock(&mux) ; 64 //cout<< "A lock" << endl ; 65 pthread_cond_wait(&cond1, &mux) ; 66 cout << "A " << i << endl ; 67 pthread_cond_signal(&cond2) ; 68 pthread_mutex_unlock(&mux) ; 69 //cout << "A unlock" << endl ; 70 } 71 cout << "thread1 is about to exit " ; 72 } 73 74 void* routine2(void* p) 75 { 76 for(int i=0; i<10; i++) 77 { 78 pthread_mutex_lock(&mux) ; 79 //cout<< "B lock" << endl ; 80 pthread_cond_wait(&cond2, &mux) ; 81 cout << "B " << i << endl ; 82 pthread_cond_signal(&cond3) ; 83 pthread_mutex_unlock(&mux) ; 84 //cout << "B unlock" << endl ; 85 } 86 cout << "thread2 is about to exit " ; 87 } 88 89 void* routine3(void* p) 90 { 91 for(int i=0; i<10; i++) 92 { 93 pthread_mutex_lock(&mux) ; 94 //cout<< "C lock" << endl ; 95 pthread_cond_wait(&cond3, &mux) ; 96 cout << "C " << i << endl ; 97 pthread_cond_signal(&cond1) ; 98 pthread_mutex_unlock(&mux) ; 99 //cout << "C unlock" << endl ; 100 } 101 cout << "thread3 is about to exit " ; 102 }
1 #include <iostream> 2 #include <thread> 3 #include <condition_variable> 4 #include <vector> 5 #include <algorithm> 6 7 std::mutex mtx; 8 std::condition_variable cvar; 9 char g_ch = 0; 10 11 void print_fun(char ch) 12 { 13 int cyle_cnt = 10; 14 char ch_ = ch - 'A'; 15 16 for (int i = 0; i < cyle_cnt; i++) 17 { 18 std::unique_lock<std::mutex>ulk(mtx); 19 cvar.wait(ulk, [ch_] {return ch_ == g_ch; }); 20 std::cout << (char)(ch_ + 'A'); 21 g_ch = (ch_ + 1) % 3; 22 ulk.unlock(); 23 24 cvar.notify_all(); 25 } 26 } 27 28 int main() 29 { 30 std::vector<std::thread> threads; 31 threads.push_back(std::thread(print_fun, 'A')); 32 threads.push_back(std::thread(print_fun, 'B')); 33 threads.push_back(std::thread(print_fun, 'C')); 34 35 std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join)); 36 37 std::cout << std::endl; 38 39 system("pause"); 40 41 return 0; 42 }
第五题(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....
请设计程序。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pthread.h> 4 #define NUM 4 5 6 pthread_mutex_t mutex; 7 pthread_cond_t cond; 8 9 int n = 0; 10 11 void *thread_func(void *argv) 12 { 13 int p = (int)argv; 14 int i; 15 16 for(i = 0; i < 10; i++) 17 { 18 pthread_mutex_lock(&mutex); 19 while(p != n) 20 { 21 pthread_cond_wait(&cond,&mutex); 22 } 23 printf("%d ",p+1); 24 n= (n + 1) % NUM; 25 pthread_mutex_unlock(&mutex); 26 pthread_cond_broadcast(&cond); 27 } 28 } 29 int main() 30 { 31 pthread_t tid[NUM]; 32 int ret; 33 int i; 34 35 pthread_mutex_init(&mutex,NULL); 36 pthread_cond_init(&cond,NULL); 37 38 for(i = 0; i< NUM; i++) 39 { 40 ret = pthread_create(&tid[i],NULL,thread_func,(void *)i); 41 if(ret == -1) 42 { 43 printf("pthread_create pid[%d] error! ",i); 44 exit(-1); 45 } 46 } 47 48 for(i = 0; i < NUM; i++) 49 { 50 ret = pthread_join(tid[i],NULL); 51 if(ret == -1) 52 { 53 printf("pthread_join pid[%d] error! ",i); 54 exit(-1); 55 } 56 } 57 printf(" "); 58 return 0; 59 }
下面的第六题与第七题也是在考研中或是程序员和软件设计师认证考试中的热门试题。
第六题
生产者消费者问题
这是一个非常经典的多线程题目,题目大意如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,所有生产者和消费者都是异步方式运行的,但它们必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经装满产品且尚未被取走的缓冲区中投放产品。
用信号量
详情查看:http://www.cnblogs.com/zl1991/p/6993225.html
第七题
读者写者问题
这也是一个非常经典的多线程题目,题目大意如下:有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写。
详情查看:http://www.cnblogs.com/zl1991/p/6987066.html
多线程相关题目就列举到此,如果各位有多线程方面的笔试面试题,欢迎提供给我,我将及时补上。谢谢大家。
下一篇《多线程第一次亲密接触 CreateThread与_beginthreadex本质区别》将从源代码的层次上讲解创建多线程的二个函数CreateThread与_beginthreadex到底有什么区别,让你明明白白的完成与多线程第一次亲密接触。
原文地址:http://blog.csdn.net/morewindows/article/details/7392749
下面列出目录,方便大家查看。
2.《秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别》
3.《秒杀多线程第三篇 原子操作 Interlocked系列函数》
8.《秒杀多线程第八篇 经典线程同步 信号量Semaphore》
9.《秒杀多线程第九篇 经典线程同步总结 关键段 事件 互斥量 信号量》
10.《秒杀多线程第十篇 生产者消费者问题》
11.《秒杀多线程第十一篇 读者写者问题》
12.《秒杀多线程第十二篇 多线程同步内功心法——PV操作上》
13.《秒杀多线程第十三篇 多线程同步内功心法——PV操作下》即将发布
14.《秒杀多线程第十四篇 读者写者问题继 读写锁SRWLock》