有四个线程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完成后,才会开始线程2,以此类推。
为了方便分析,我们将题目要求的格式进行转换,给出每次循环每个线程写入的目标文件,格式如下:
可以分析出,下一轮循环写入的文件有如下格式:
static char szFileName[4][32] ={
"A.txt",
"B.txt",
"C.txt",
"D.txt"
};
NextLoopFile([i+1) % 4] = CurrentFile[i]
我们利用C++11中提供的条件变量完成完成题目要求:
具体代码如下:
#include <thread>
#include <fstream>
#include <condition_variable>
#include <mutex>
std::condition_variable g_cvWriter;
std::mutex g_mutex_writer;
const unsigned MAX_THREAD_NUM = 4;
const unsigned MAX_LOOP_NUM = 10;
//控制线程执行流程
unsigned g_nNextThreadID = 0;
//每一轮的文件ID
unsigned g_nCurrentFileIndex[MAX_THREAD_NUM] = { 0, 1, 2, 3};
//文件名
char g_szFileName[MAX_THREAD_NUM][32] = {
"A.txt",
"B.txt",
"C.txt",
"D.txt"
};
//每个线程输出的字符
char GetChar(unsigned nID)
{
return nID + '1';
}
// 每一轮的文件ID
void GetNextLoopFileIndex()
{
unsigned nNewLoopFileName[MAX_THREAD_NUM] = { 0 };
//C[i] = N[(i+1)%max_num]
for (int i = 0; i < MAX_THREAD_NUM; i++)
{
nNewLoopFileName[(i + 1) % MAX_THREAD_NUM] = g_nCurrentFileIndex[i];
}
memcpy(g_nCurrentFileIndex, nNewLoopFileName, sizeof(nNewLoopFileName));
}
char* GetFileName(unsigned nID)
{
return g_szFileName[g_nCurrentFileIndex[nID]];
}
void WriterChar2File(const char* szFileName, char ch)
{
std::fstream file(szFileName, std::ostream::out | std::ostream::app);
file << ch;
file << std::endl;
}
//nID从 0 1 2 3
void WriterCharThread(unsigned nID)
{
for (int i = 0; i < MAX_LOOP_NUM; i++)
{
std::unique_lock<std::mutex> lk(g_mutex_writer);
//线程同步
g_cvWriter.wait(lk, [=](){ return nID == g_nNextThreadID; });
char ch = GetChar(nID);
const char* pszFileName = GetFileName(nID);
WriterChar2File(pszFileName, ch);
g_nNextThreadID++;
//新一轮的开始
if (nID + 1 == MAX_THREAD_NUM)
{
GetNextLoopFileIndex();
g_nNextThreadID = 0;
}
//唤醒所有被挂起的线程,同时检查是否满足条件 ,满足条件的会继续执行
g_cvWriter.notify_all();
}
}
void main_thread()
{
std::thread arrThread[MAX_THREAD_NUM];
for (unsigned i = 0; i < MAX_THREAD_NUM; i++)
{
arrThread[i] = std::thread(WriterCharThread, i);
}
for (int i = 0; i < MAX_THREAD_NUM; i++)
{
arrThread[i].join();
}
}
运行结果: