更多C++多线程面试题,见一份多线程面试题及参考答案
目录
有四个线程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....
请设计程序。
创建线程
创建线程优先使用_beginthreadex()
头文件:
#include <process.h>
函数定义:
unsigned long _beginthreadex(
void *security,
unsigned stack_size,
unsigned ( __stdcall *start_address )( void * ),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
security :线程的安全属性,NULL表示默认安全属性
stack_size:线程的堆栈大小,一般默认0
start_address:启动函数地址
arglist:参数列表,传递多个参数时用结构体,传结构体指针
initflag:新线程的初始状态,0表示立即执行,CREATE_SUSPEND(0x00000004)表示挂起
thrdaddr:用来接收线程ID
for (i = 0; i < THREAD_NUM; i++)
hdl[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, (void*)i, 0, NULL);
C++文件读写ofstream
#include <fstream>
using namespace std;
ofstream //文件写操作 内存写入存储设备
ifstream //文件读操作,存储设备读区到内存中
fstream //读写操作,对打开的文件可进行读写操作
这里主要讲ofstream,ofstream是从内存到硬盘,其实所谓的流缓冲就是内存空间。
void open(const char* filename,int mode,int access);
参数:
filename: 要打开的文件名
mode: 要打开文件的方式
access: 打开文件的属性
mode:打开文件的方式在ios类(所以流式I/O的基类)中定义,有如下几种方式:
ios::in | 为输入(读)而打开文件 |
ios::out | 为输出(写)而打开文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 所有输出附加在文件末尾 |
ios::trunc | 如果文件已存在则先删除该文件 |
ios::binary | 二进制方式 |
这些方式是能够进行组合使用的,以“或”运算(“|”)的方式打开文件的属性同样在ios类中也有定义:
0 | 普通文件,打开操作 |
1 | 只读文件 |
2 | 隐含文件 |
4 | 系统文件 |
对于文件的属性也可以使用“或”运算和“+”进行组合使用,这里就不做说明了。
互斥变量:临界区
#include <windows.h>
CRITICAL_SECTION g_csFile;
//进入临界区
InitializeCriticalSection(&g_csFile);
EnterCriticalSection(&g_csfile);
LeaveCriticalSection(&g_csfile);
DeleteCriticalSection(&g_csFile);
事件
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // 1.安全属性
BOOL bManualReset, // 2.复位方式,是否为手动
BOOL bInitialState, // 3.初始状态,是否有信号
LPCTSTR lpName //4.对象名称
);
一般参数1和参数4为NULL
参数2,bManualReset,指定将事件对象创建成手动复原还是自动复原。
如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。
如果设置为FALSE,当事件被一个等待线程释放以后,系统将会自动将事件状态复原为无信号状态
参数3,bInitialState,指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态;否则为无信号状态。
CreateEvent(NULL, FALSE, FALSE, NULL)
创建的事件,初始状态为无信号状态,事件被释放后,自动复原为无信号状态。
CEvent::SetEvent()把对象设置为有信号状态
WaitForSingleObject(g_hThreadEvent[num], INFINITE);
DWORD WaitForSingleObject( HANDLE hHandle, DWORDdwMilliseconds);
有两个参数,分别是THandle和Timeout(毫秒单位)。
如果想要等待一条线程,那么你需要指定线程的Handle,以及相应的Timeout时间。当然,如果你想无限等待下去,Timeout参数可以指定系统常量INFINITE。
此处等待g_hThreadEvent[num]有信号,即等待SetEvent(ThreadEvent[num])激活事件信号。
下一轮线程1,2,3,4要操作的文件编号
NEXT_LOOP[FILE_NUM] = { 0,1,2,3, }
代表线程1,2,3,4分别要输出的文件编号,
第一轮线程1输出文件A,线程2输出文件B,线程3输出文件C ,线程输出文件D
第二轮,线程1输出文件D,线程2输出文件A,线程3输出文件B,线程4输出文件C,则
NEXT_LOOP[FILE_NUM] = { 3,0,1,2, }
第三轮:
NEXT_LOOP[FILE_NUM] = { 2,3,0,1, }
即,下一轮线程要操作的文件编号为:
NEXT_LOOP[(num + 1) % (FILE_NUM)] = FILE_THREAD[num];
源代码:
// HJ49_m多线程.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <fstream>
using namespace std;
CRITICAL_SECTION g_csfile;
//线程个数
const int THREAD_NUM = 4;
unsigned int __stdcall Fun(void *pPM);
//文件个数
const int FILE_NUM = 4;
ofstream file[FILE_NUM];
//互斥事件
HANDLE g_hThreadEvent[THREAD_NUM];
HANDLE g_OK;
//每个线程输出的字符个数
const int Loop = 6;
//某个线程要写入的文件
int FILE_THREAD[FILE_NUM] = { 0,1,2,3 };
int NEXT_LOOP[FILE_NUM] = { 0,1,2,3 };
int main()
{
InitializeCriticalSection(&g_csfile);
//1.创建线程
HANDLE hdl[THREAD_NUM];
for (int i = 0; i < THREAD_NUM;i++)
{
hdl[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, (void*)i, 0, NULL);
}
//3.创建线程互斥事件并激活线程1
for (int i = 0; i < THREAD_NUM; i++)
{
g_hThreadEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
}
g_OK = CreateEvent(NULL, FALSE, FALSE, NULL);
//2.打开文件
char filename[] = "A.txt";
for (int i = 0; i < FILE_NUM;i++)
{
filename[0] = i + 'A';
file[i].open(filename, ios::trunc);
if (file[i].fail())
{
printf("打开文件%s失败", filename);
continue;
}
}
SetEvent(g_hThreadEvent[0]);
//4.等待线程完成6次打印
//WaitForMultipleObjects(THREAD_NUM, g_hThreadEvent, TRUE, INFINITE);
WaitForSingleObject(g_OK,INFINITE);
printf("最后结果:");
//5.销毁线程
for (int i = 0; i < THREAD_NUM;i++)
{
CloseHandle(hdl[i]);
CloseHandle(g_hThreadEvent[i]);
}
//6.关闭文件流:
for (int i = 0; i < FILE_NUM;i++)
{
file[i].close();
}
DeleteCriticalSection(&g_csfile);
return 0;
}
//7.实现线程函数
unsigned int __stdcall Fun(void *pPM)
{
//当前线程id
int num = (int)pPM;
for (int i = 0; i < Loop;i++)
{
WaitForSingleObject(g_hThreadEvent[num], INFINITE);
EnterCriticalSection(&g_csfile);
printf(" 线程 %d 正在向%c文件写入,下一次对%c文件进行操作的是线程%d\n",num+1,FILE_THREAD[num]+'A', FILE_THREAD[num] + 'A',(num+1)%(THREAD_NUM)+1);
file[FILE_THREAD[num]] << num + 1 << " ";
Sleep(200);
NEXT_LOOP[(num + 1) % FILE_NUM] = FILE_THREAD[num];
if(num + 1 == FILE_NUM)
{
printf("\n");
memcpy(FILE_THREAD, NEXT_LOOP, sizeof(int)*FILE_NUM);
}
LeaveCriticalSection(&g_csfile);
SetEvent(g_hThreadEvent[(num + 1) % THREAD_NUM]);
}
if (num + 1 == THREAD_NUM)
{
SetEvent(g_OK);
}
return 0;
}