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…
请设计程序。 [讲解:https://www.cnblogs.com/waterfall/p/7994384.html]
#include <thread>
#include <vector>
#include <condition_variable>
#include <mutex>
#include <map>
#include <semaphore.h>
#define MaxThreadNums 4
#define MaxCycleNums 7
namespace me {
class Semaphore {
public:
Semaphore(long count = 0)
: count_(count) {
}
void signal() {
std::unique_lock<std::mutex> lock(mutex_);
++count_;
cv_.notify_one();
}
void wait() {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [=] { return count_ > 0; });
--count_;
}
private:
std::mutex mutex_;
std::condition_variable cv_;
long count_;
};
}
class File {
public:
File() {}
void Write(char c) {
std::unique_lock<std::mutex> Guard(mtx_);
buffer_ += c;
}
std::string GetBuffer() {
std::unique_lock<std::mutex> Guard(mtx_);
return buffer_;
}
private:
std::mutex mtx_;
std::string name_;
std::string buffer_;
size_t pos_;
};
/*
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....
*/
#if 10
#define sem_init
me::Semaphore sem_a{1};
me::Semaphore sem_b{1};
me::Semaphore sem_c{1};
me::Semaphore sem_d{1};
me::Semaphore *sems[] = {&sem_a, &sem_b, &sem_c, &sem_d};
#else
sem_t sem_a;
sem_t sem_b;
sem_t sem_c;
sem_t sem_d;
sem_t *sems[] = {&sem_a, &sem_b, &sem_c, &sem_d};
#endif
int sem_wait(me::Semaphore *sem) {
sem->wait();
return 0;
}
int sem_post(me::Semaphore *sem) {
sem->signal();
return 0;
}
using ThreadTag = uint8_t;
using PosIdx = uint8_t ;
class ThreadInfo {
public:
ThreadInfo(ThreadTag id) : id_(id) {
}
void WriteToFile(File &file) {
file.Write(GetData());
}
uint8_t GetId() {
return id_;
}
char GetData() {
return '1' + id_;
}
private:
ThreadTag id_;
};
class WriteHelper {
public:
explicit WriteHelper(ThreadInfo &info) {
pos_ = GetInitPosIndex(info.GetId());
}
File &GetFileHandler() {
uint8_t idx = index_[pos_++ % MaxThreadNums];
return GetFiles()[idx];
}
private:
PosIdx index_[4] = {0, 3, 2, 1};
PosIdx pos_;
public:
static PosIdx GetInitPosIndex(ThreadTag id) {
thread_local std::map<ThreadTag, PosIdx> map_;
if (map_.empty()) {
// thread -> init index
map_[0] = 0;
map_[1] = 3;
map_[2] = 2;
map_[3] = 1;
}
return map_[id];
}
static File *GetFiles() {
static File files_[MaxThreadNums];
return files_;
}
};
// th sched: A -> B -> C -> D
void fun(ThreadInfo info) {
WriteHelper helper(info);
for (int i = 0; i < MaxCycleNums; i++) {
sem_wait(sems[info.GetId()]);
// printf("my_name: %c, %d\n", info.GetId(), info.GetData());
info.WriteToFile(helper.GetFileHandler());
sem_post(sems[(info.GetId() + 1) % MaxThreadNums]);
}
}
int main() {
sem_init(&sem_a, 0, 1);
sem_init(&sem_b, 0, 1);
sem_init(&sem_c, 0, 1);
sem_init(&sem_d, 0, 1);
std::thread ths[MaxThreadNums];
for (int i = 0; i < MaxThreadNums; ++i) {
ths[i] = std::thread(fun, ThreadInfo(i));
}
for (int i = 0; i < MaxThreadNums; ++i) {
auto &th = ths[i];
if (th.joinable()) {
th.join();
// printf("exit th:%d\n", i);
}
}
for (int i = 0; i < MaxThreadNums; ++i) {
auto buf = WriteHelper::GetFiles()[i].GetBuffer();
printf("buf %c: %s\n", i + 'A', buf.c_str());
}
printf("\nmain is over\n");
}
