您的位置:首页 > 运维架构 > Linux

linux--多线程--面试题

2015-03-20 15:33 288 查看
刚无意中看到MoreWindows博主秒杀多线程面试题(http://blog.csdn.net/column/details/killthreadseries.html),第一篇就有他收集的面试题。那我就用来检验一下自己学的怎么样吧。

前面的选择题那些跳过,直接看最后的编程题。

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

子线程循环 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....

请设计程序。

第六题

生产者消费者问题

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

第七题

读者写者问题

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

第三题、第四题、第五题第一反应用条件变量来实现。第六题和第七题用读写锁来实现。

第三题、第四题、第五题和我上一篇博客linux多线程学习举得那例子很相似,只需要少量修改就能完成要求。不多说,直接上代码。

第四题代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
//#define DEBUG 1
#define NUM 3

int n=0;
pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;//互斥量
pthread_cond_t qready=PTHREAD_COND_INITIALIZER;//条件变量
void * thread_func(void *arg)
{
int param=(int)arg;
char c='A'+param;
int ret,i=0;
for (; i < 10; i++)
{
pthread_mutex_lock(&mylock);
while (param != n)
{
#ifdef DEBUG
printf("thread %d waiting\n", param);
#endif
ret = pthread_cond_wait(&qready, &mylock);
if (ret == 0)
{
#ifdef DEBUG
printf("thread %d wait success\n", param);
#endif
} else
{
#ifdef DEBUG
printf("thread %d wait failed:%s\n", param, strerror(ret));
#endif
}
}
// printf("%d ",param+1);
printf("%c ",c);
n=(n+1)%NUM;
pthread_mutex_unlock(&mylock);
pthread_cond_broadcast(&qready);
}
return (void *)0;
}
int main(int argc, char** argv) {

int i=0,err;
pthread_t tid[NUM];
void *tret;
for(;i<NUM;i++)
{
err=pthread_create(&tid[i],NULL,thread_func,(void *)i);
if(err!=0)
{
printf("thread_create error:%s\n",strerror(err));
exit(-1);
}
}
for (i = 0; i < NUM; i++)
{
err = pthread_join(tid[i], &tret);
if (err != 0)
{
printf("can not join with thread %d:%s\n", i,strerror(err));
exit(-1);
}
}
printf("\n");
return 0;
}


运行结果:



第五题:

选项A,代码只需要将NUM改为4,printf("%c ",c)改为printf("%d ",param+1);即可

执行结果如下:



选项B,将全局变量n改为1



选项C,将全局变量n改为2



选项D,将全局变量n改为3



下班啦。。后面两道题,等等在贴出代码。。

第六题

方法一,采用互斥量来实现生产者和消费者的同步。

流程图如下所示:



生产者:

对互斥量加锁
判断缓冲区是否已满,如满,则跳到步骤4
放入产品
解锁互斥量,此时一个循环完成,进入下一循环。

消费者流程图类似与生产者流程图。

代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define NUMS 10  //表示生产,消费的次数
#define CAPACITY 5 //定义缓冲区最大值
int capacity = 0; //当前缓冲区的产品个数
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;//互斥量

void *produce(void *args)
{
int i = 0;
for (; i < NUMS; )
{
pthread_mutex_lock(&mylock);//加锁
if (capacity >= CAPACITY) //当前产品个数大于等于缓冲区最大值,则不把产品放入缓冲区。
{
printf("缓冲区已满,无法放入产品\n");
} else {//将产品放入缓冲区
++capacity;
printf("生产者存入一个产品, 缓冲区大小为:%d\n", capacity);
i++;
}
pthread_mutex_unlock(&mylock);
}
return ((void *) 0);
}

void * consume(void *args)
{
int i = 0;
for (; i < NUMS; )
{
pthread_mutex_lock(&mylock);
if (capacity > 0)
{
--capacity;
printf("消费者消耗一个产品,缓冲区大小为:%d\n", capacity);
i++;
} else
{
printf("缓冲区已空,无法消耗产品\n");
}
pthread_mutex_unlock(&mylock);
}
return ((void *) 0);
}

int main(int argc, char** argv) {

int err;
pthread_t produce_tid, consume_tid;
void *ret;
err = pthread_create(&produce_tid, NULL, produce, NULL);//创建线程
if (err != 0)
{
printf("线程创建失败:%s\n", strerror(err));
exit(-1);
}
err = pthread_create(&consume_tid, NULL, consume, NULL);
if (err != 0)
{
printf("线程创建失败:%s\n", strerror(err));
exit(-1);
}
err = pthread_join(produce_tid, &ret);//主线程等到子线程退出
if (err != 0)
{
printf("生产着线程分解失败:%s\n", strerror(err));
exit(-1);
}
err = pthread_join(consume_tid, &ret);
if (err != 0)
{
printf("消费者线程分解失败:%s\n", strerror(err));
exit(-1);
}
return (EXIT_SUCCESS);
}


执行结果:



结果满足题意。但是这存在一个问题,极端情况下,生产者每次都加锁成功,那缓冲区会满,产品无法放入缓冲区。消费者会被饿死,因为他一直无法获得互斥量。方法二,解决了导致某一方饿死的可能性。

update:

在第一种方法中,当缓冲区满时,让生产者睡眠;当缓冲区空,让消费者睡眠。这样也能解决某一方老是加锁成功。

方法二:采用两个互斥量来完成

流程图如下:



运行截图:



上代码:

/*
* File:   main.c
* Author: root
*
* Created on 2012年5月22日, 上午9:35
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define NUMS 10  //表示生产,消费的次数
#define CAPACITY 5 //定义缓冲区最大值

int capacity = 0; //当前缓冲区的产品个数
pthread_mutex_t mylockA=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mylockB=PTHREAD_MUTEX_INITIALIZER;

void *produce(void *args)
{
int i = 0,err;
for (; i < NUMS; )
{
pthread_mutex_lock(&mylockA);//加锁
if (capacity >= CAPACITY) //当前产品个数大于等于缓冲区最大值,则不把产品放入缓冲区。
{
printf("缓冲区已满,无法放入产品\n");
} else {//将产品放入缓冲区
++capacity;
printf("生产者存入一个产品, 产品个数:%d\n", capacity);
i++;
}
err=pthread_mutex_unlock(&mylockB);
}
return ((void *) 0);
}

void * consume(void *args)
{
int i = 0;
for (; i < NUMS; )
{
pthread_mutex_lock(&mylockB);
if (capacity > 0)
{
--capacity;
printf("消费者消耗一个产品,产品个数:%d\n", capacity);
i++;
} else
{
printf("缓冲区已空,无法消耗产品\n");
}
pthread_mutex_unlock(&mylockA);
}
return ((void *) 0);
}

int main(int argc, char** argv) {

int err;
pthread_t produce_tid, consume_tid;
void *ret;
if(capacity==0)
pthread_mutex_lock(&mylockB);
else
if(capacity==CAPACITY)
pthread_mutex_lock(&mylockA);
err = pthread_create(&produce_tid, NULL, produce, NULL);//创建线程
if (err != 0)
{
printf("线程创建失败:%s\n", strerror(err));
exit(-1);
}
err = pthread_create(&consume_tid, NULL, consume, NULL);
if (err != 0)
{
printf("线程创建失败:%s\n", strerror(err));
exit(-1);
}
err = pthread_join(produce_tid, &ret);//主线程等到子线程退出
if (err != 0)
{
printf("生产着线程分解失败:%s\n", strerror(err));
exit(-1);
}
err = pthread_join(consume_tid, &ret);
if (err != 0)
{
printf("消费者线程分解失败:%s\n", strerror(err));
exit(-1);
}
return (EXIT_SUCCESS);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: