linux-多線程--面試題

 剛無意中看到MoreWindows博主秒殺多線程面試題(http://blog.csdn.net/column/details/killthreadseries.html),第一篇就有他收集的面試題。那我就用來檢驗一下自己學的怎麼樣吧。 

   前面的選擇題那些跳過,直接看最後的編程題。

第三題(某培訓機構的練習題):

子線程循環 10 次,接着主線程循環 100 次,接着又回到子線程循環 10 次,接着再回到主線程又循環 100 次,如此循環50次,試寫出代碼。


第四題(迅雷筆試題):

編寫一個程序,開啓3個線程,這3個線程的ID分別爲ABC,每個線程將自己的ID在屏幕上打印10遍,要求輸出結果必須按ABC的順序顯示;如:ABCABC.依次遞推。


第五題(Google面試題)

有四個線程1、234。線程1的功能就是輸出1,線程2的功能就是輸出2,以此類推.........現在有四個文件ABCD。初始都爲空。現要讓四個文件呈如下格式:

A1 2 3 4 1 2....

B2 3 4 1 2 3....

C3 4 1 2 3 4....

D4 1 2 3 4 1....

請設計程序。

第六題

生產者消費者問題

這是一個非常經典的多線程題目,題目大意如下:有一個生產者在生產產品,這些產品將提供給若干個消費者去消費,爲了使生產者和消費者能併發執行,在兩者之間設置一個有多個緩衝區的緩衝池,生產者將它生產的產品放入一個緩衝區中,消費者可以從緩衝區中取走產品進行消費,所有生產者和消費者都是異步方式運行的,但它們必須保持同步,即不允許消費者到一個空的緩衝區中取產品,也不允許生產者向一個已經裝滿產品且尚未被取走的緩衝區中投放產品。


第七題

讀者寫者問題

這也是一個非常經典的多線程題目,題目大意如下:有一個寫者很多讀者,多個讀者可以同時讀文件,但寫者在寫文件時不允許有讀者在讀文件,同樣有讀者讀時寫者也不能寫。

新增第八題:

是否熟悉POSIX多線程編程技術?如熟悉,編寫程序完成如下功能:

1)有一int型全局變量g_Flag初始值爲0;

2) 在主線稱中起動線程1,打印“this is thread1”,並將g_Flag設置爲1

3) 在主線稱中啓動線程2,打印“this is thread2”,並將g_Flag設置爲2

4) 線程序1需要在線程2退出後才能退出

5) 主線程在檢測到g_Flag從1變爲2,或者從2變爲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



下班啦。。後面兩道題,等等在貼出代碼。。


第六題

方法一,採用互斥量來實現生產者和消費者的同步。
流程圖如下所示:

生產者:
  1. 對互斥量加鎖
  2. 判斷緩衝區是否已滿,如滿,則跳到步驟4
  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);
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章