c++并发面试题

秒杀多线程第一篇 多线程笔试面试题汇总:
https://blog.csdn.net/morewindows/article/details/7392749

50个多线程面试题,你会多少?
https://blog.csdn.net/cmyperson/article/details/79610870

多线程的40个面试题总结(上)
https://blog.csdn.net/u012459345/article/details/51179578

Linux的多线程的一些面试题:
https://blog.csdn.net/chencheng126/article/details/44587691?utm_source=blogxgwz7

那些年遇到过的面试题 - 40个多线程问题总结:
https://blog.csdn.net/lis_12/article/details/54380521

https://www.cppfans.org/2167.html

https://blog.csdn.net/phiall/article/details/52385165

https://blog.csdn.net/charles_r_chiu/article/details/79975297

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

#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;
mutex m;
condition_variable cond;
int flag=10;
void fun(int num){
    for(int i=0;i<50;i++){
        unique_lock<mutex> lk(m);//A unique lock is an object that manages a mutex object with unique ownership in both states: locked and unlocked.
        while(flag!=num)
            cond.wait(lk);//在调用wait时会执行lk.unlock()
        for(int j=0;j<num;j++)
            cout<<j<<" ";
        cout<<endl;
        flag=(num==10)?100:10;
        cond.notify_one();//被阻塞的线程唤醒后lk.lock()恢复在调用wait前的状态
    }
}
int main(){
    thread child(fun,10);
    fun(100);
    child.join();
    return 0;
}

2、是否熟悉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的时候退出

#include<iostream>  
#include<functional>  
#include<thread>  
#include<future>  
#include<utility>  
#include<stdio.h>  
#include<chrono>  
#include<atomic>  
#include<condition_variable>
//#include<pthread.h>  
using namespace std;
atomic<int> flag(0);//采用原子操作保护g_Flag的读写  
mutex m;
condition_variable cond1;
condition_variable cond2;
condition_variable cond3;
 
void worker1(int f1){//线程1  
	unique_lock<mutex>lk(m);
	
	printf("this is thread%d\n",f1);
	flag = 1;
	cond3.notify_one();
	while (flag != 2)
		cond1.wait(lk);
	printf("thread1 exit\n");
	cond3.notify_one();
}
 
void worker2(int f2){//线程1  
	unique_lock<mutex>lk(m);
	while (1 != flag)
		cond3.wait(lk);
	printf("this is thread%d\n", f2);
	printf("thread2 exit\n");
	   flag = 2;
	cond1.notify_all();
}
 
 
int main(){
	
	thread one(worker1, 1);
	thread two(worker2, 2);
	 
	one.detach();
	two.detach();
	//pthread_exit(NULL);//主线程到这里退出  
 
	unique_lock<mutex>lk(m);
		cond3.wait(lk);
	printf("main thread exit\n");
	return 0;
}

3、线程的基本概念、线程的基本状态及状态之间的关系?
线程是CPU使用的基本单元;它由线程ID、程序计数器、寄存器集合和堆栈组成。它与属于同一进程的其他线程共享其代码段、数据段和其他操作系统资源(如打开文件和信号)。
线程有四种状态:新生状态、可运行状态、被阻塞状态、死亡状态。

4、多线程有几种实现方法,都是什么?
(1)继承 Thread 类 (2) 实现 Runnable 接口再 new Thread(YourRunnableOjbect)

5、以下多线程对int型变量x的操作,哪几个不需要进行同步(D)
A. x=y; B. x++; C. ++x; D. x=1;

6、多线程中栈与堆是公有的还是私有的 (C)

    A:栈公有, 堆私有

    B:栈公有,堆公有

    C:栈私有, 堆公有

    D:栈私有,堆私有

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

int inttally = 0;//glable

    voidThreadProc()

    {

          for(inti = 1;i <= 50;i++)

               tally += 1;

    }
    答:[50,100]

8、编写一个程序,开启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 <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

mutex m;
condition_variable cond;
int count = 0;

void func(int num)
{
    for (int i = 0;i < 10;i++)
    {
        unique_lock<mutex> ulk(m);
        while(count != num)
        {
            cond.wait(ulk);
        }

        char ch = (num  + 'A'); 
        cout << ch << endl;
        count = (count + 1) % 3;

        cond.notify_all();
    }
}

int main()
{
    int i = 0;
    thread thread1(func, 0);
    thread thread2(func, 1);
    thread thread3(func, 2);

    thread1.join();
    thread2.join();
    thread3.join();

    return 0;
}

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

分析:假设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;
}

10、有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写。

分析:首先来找找哪些是属于“等待”情况。第一、写者要等到没有读者时才能去写文件。第二、所有读者要等待写者完成写文件后才能去读文件。找完“等待”情况后,再看看有没有要互斥访问的资源。由于只有一个写者而读者们是可以共享的读文件,所以按题目要求并没有需要互斥访问的资源。代码如下:

#include "stdafx.h"  
#include "stdio.h"  
#include "stdlib.h"  
#include <iostream>  
#include <string>  
#include <stack>  
#include <windows.h>  
#include <process.h>  
using namespace std;  
  
//读者与写者问题  
#include <stdio.h>  
#include <process.h>  
#include <windows.h>  
//设置控制台输出颜色  
BOOL SetConsoleColor(WORD wAttributes)  
{  
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);  
    if (hConsole == INVALID_HANDLE_VALUE)  
        return FALSE;  
      
    return SetConsoleTextAttribute(hConsole, wAttributes);  
}  
const int READER_NUM = 5;  //读者个数  
//关键段和事件  
CRITICAL_SECTION g_cs, g_cs_writer_count;  
HANDLE g_hEventWriter, g_hEventNoReader;  
int g_nReaderCount;  
//读者线程输出函数(变参函数的实现)  
void ReaderPrintf(char *pszFormat, ...)  
{  
    va_list   pArgList;  
      
    va_start(pArgList, pszFormat);  
    EnterCriticalSection(&g_cs);  
    vfprintf(stdout, pszFormat, pArgList);  
    LeaveCriticalSection(&g_cs);  
    va_end(pArgList);  
}  
//读者线程函数  
unsigned int __stdcall ReaderThreadFun(PVOID pM)  
{  
    ReaderPrintf("     编号为%d的读者进入等待中...\n", GetCurrentThreadId());  
    //等待写者完成  
    WaitForSingleObject(g_hEventWriter, INFINITE);  
  
    //读者个数增加  
    EnterCriticalSection(&g_cs_writer_count);  
    g_nReaderCount++;  
    if (g_nReaderCount == 1)  
        ResetEvent(g_hEventNoReader);  
    LeaveCriticalSection(&g_cs_writer_count);  
  
    //读取文件  
    ReaderPrintf("编号为%d的读者开始读取文件...\n", GetCurrentThreadId());  
  
    Sleep(rand() % 100);  
  
    //结束阅读,读者个数减小,空位增加  
    ReaderPrintf(" 编号为%d的读者结束读取文件\n", GetCurrentThreadId());  
  
    //读者个数减少  
    EnterCriticalSection(&g_cs_writer_count);  
    g_nReaderCount--;  
    if (g_nReaderCount == 0)  
        SetEvent(g_hEventNoReader);  
    LeaveCriticalSection(&g_cs_writer_count);  
  
    return 0;  
}  
//写者线程输出函数  
void WriterPrintf(char *pszStr)  
{  
    EnterCriticalSection(&g_cs);  
    SetConsoleColor(FOREGROUND_GREEN);  
    printf("     %s\n", pszStr);  
    SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);  
    LeaveCriticalSection(&g_cs);  
}  
//写者线程函数  
unsigned int __stdcall WriterThreadFun(PVOID pM)  
{  
    WriterPrintf("写者线程进入等待中...");  
    //等待读文件的读者为零  
    WaitForSingleObject(g_hEventNoReader, INFINITE);  
    //标记写者正在写文件  
    ResetEvent(g_hEventWriter);  
          
    //写文件  
    WriterPrintf("  写者开始写文件.....");  
    Sleep(rand() % 100);  
    WriterPrintf("  写者结束写文件");  
  
    //标记写者结束写文件  
    SetEvent(g_hEventWriter);  
    return 0;  
}  
  
int main()  
{  
    printf("  读者写者问题\n");  
    printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");  
  
    //初始化事件和信号量  
    InitializeCriticalSection(&g_cs);  
    InitializeCriticalSection(&g_cs_writer_count);  
  
    //手动置位,初始已触发  
    g_hEventWriter = CreateEvent(NULL, TRUE, TRUE, NULL);  
    g_hEventNoReader  = CreateEvent(NULL, FALSE, TRUE, NULL);  
    g_nReaderCount = 0;  
  
    int i;  
    HANDLE hThread[READER_NUM + 1];  
    //先启动二个读者线程  
    for (i = 1; i <= 2; i++)  
        hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);  
    //启动写者线程  
    hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);  
    Sleep(50);  
    //最后启动其它读者结程  
    for ( ; i <= READER_NUM; i++)  
        hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);  
    WaitForMultipleObjects(READER_NUM + 1, hThread, TRUE, INFINITE);  
    for (i = 0; i < READER_NUM + 1; i++)  
        CloseHandle(hThread[i]);  
  
    //销毁事件和信号量  
    CloseHandle(g_hEventWriter);  
    CloseHandle(g_hEventNoReader);  
    DeleteCriticalSection(&g_cs);  
    DeleteCriticalSection(&g_cs_writer_count);  
    return 0;  
}  
  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值