我是多线程新手,所以任何建议都将非常有用!我正在根据以下要求实现多线程程序:
答案 0 :(得分:0)
问题中的代码给我一些关于应该如何进行复制的不确定性,但是我做出了以下假设:
我将用来完成概述的模拟的方案是拥有一个控制time
变量的线程,该线程可以是主线程,也可以是专门为此目的创建的线程。该线程将根据需要增加时间,但是将等待所有线程检查其单元是否已死亡或需要在两次增加之间重现并执行必要的操作。下面的示例演示了这种方法。
我发现使用std::atomic
变量存储活细胞数,模拟时间,需要检查的线程数等时,这会更容易一些,甚至可能更清楚。使用原子变量时,则对于任何增量或减量都将执行必要的内存防护,而无需进行std::mutex
或其他显式同步。此外,最好为单元格实现class
,这样,它们就可以存储自己的生命(如果它们仍然存活,无论是孩子还是父母,是否有孩子等)。< / p>
#include <iostream>
#include <thread>
#include <atomic>
#include <vector>
#include <mutex>
class Cell {
public:
Cell(int x, bool child = false) {
lifetime = (0.1 + x % 8);
n = x;
is_child = child;
alive = true;
has_children = false;
}
int lifetime;
int n;
bool is_child;
bool has_children;
bool alive;
};
std::mutex mtx; // This will be used to synchronize threads.push_back()
// when creating children cells
std::vector<Cell> cells;
std::vector<std::thread> threads;
std::atomic<int> t; // The simulation time
std::atomic<int> living; // The number of living cells
std::atomic<int> check; // This will be used to ensure every thread goes through the
// necessary checks every time step
void thread_function(Cell cell) {
int prev = t;
while (living > 0) {
while (prev == t) {if (living == 0) return;}
prev = (int)t;
if (!cell.has_children && !cell.is_child && t > cell.lifetime / 2.0) {
cell.has_children = true;
// Create children and send them to new threads
for (int ii = 0; ii < ((cell.n - cell.n % 8) / 8); ii ++) {
living ++;
Cell c(ii, true); // Create a new cell which will die
c.lifetime = cell.lifetime + t; // {lifetime} seconds from now
mtx.lock();
threads.push_back(std::thread(thread_function, c));
mtx.unlock();
}
}
if (cell.alive && t >= cell.lifetime) {
cell.alive = false;
living --;
}
check --;
}
}
int main(int argn, char** argv) {
living = argn - 1;
if (argn > 1) {
for (int ii = 1; ii < argn; ii ++) {
cells.push_back(Cell(atoi(argv[ii])));
threads.push_back(std::thread(thread_function, cells[ii-1]));
}
}
t = 0;
while (living > 0) {
std::cout << "Total Cells: "+std::to_string(living)+" [ "+std::to_string(t)+
" s ]\n" << std::flush;
check = threads.size();
t ++;
while (check > 0) {
if (living == 0) break;
}
}
std::cout << "Total Cells: "+std::to_string(living)+" [ "+std::to_string(t)+
" s ]\n" << std::flush;
for (int ii = 0; ii < threads.size(); ii ++) {
threads[ii].join();
}
}
./cells 1 2 3 4 5 6 7
Total Cells: 7 [ 0 s ]
Total Cells: 6 [ 1 s ]
Total Cells: 5 [ 2 s ]
Total Cells: 4 [ 3 s ]
Total Cells: 3 [ 4 s ]
Total Cells: 2 [ 5 s ]
Total Cells: 1 [ 6 s ]
Total Cells: 0 [ 7 s ]
./cells 21 12 6 7 1 17 25
Total Cells: 7 [ 0 s ]
Total Cells: 9 [ 1 s ]
Total Cells: 4 [ 2 s ]
Total Cells: 7 [ 3 s ]
Total Cells: 6 [ 4 s ]
Total Cells: 5 [ 5 s ]
Total Cells: 4 [ 6 s ]
Total Cells: 2 [ 7 s ]
Total Cells: 0 [ 8 s ]
使用互斥锁,可以通过包围check
,t
和living
的每个增量和减量来获得相同的结果。
注意,按照我的习惯使用全局变量并不是一个好习惯,我这样做只是为了简化多线程的演示,实际上,最好将它们包装在{{1}中},将整个模拟重构为namespace
等。