在函数中传递矢量元素

时间:2019-12-26 11:37:46

标签: c++ multithreading c++11 multiprocessing

我是多线程新手,所以任何建议都将非常有用!我正在根据以下要求实现多线程程序:

  • 用户输入整数列表作为矢量。每个向量元素N代表一个单元格。
  • 将矢量元素传递给线程函数,通过该函数可以计算出特定时间的总细胞数
  • 计算电池的寿命(0.1 + N%8秒)。在生命的一半时,它们繁殖了许多((N – N%8)/ 8)个子细胞。
  • 子细胞的寿命与其父细胞相同,但是当它们的寿命结束时,它们会死而不会繁殖。
  • 在创建第一个创始单元线程之前,将启动一个单元监视器。监视器将每秒打印出现有的活细胞数量,以便监视有多少个活细胞。
  • 主要功能正在等待用户输入。给定向量输入,它将启动 监视线程,然后启动创世细胞线程。

1 个答案:

答案 0 :(得分:0)

问题中的代码给我一些关于应该如何进行复制的不确定性,但是我做出了以下假设:

  • (((N-N%8)/ 8)是指每个亲本 N 会产生多少子细胞,当其寿命达到一半时,不是所讨论的代码所暗示的
  • 从创建之初起,子细胞就与父母生活相同的时间-因此,他们比父母活了很多,而不是同时死亡,这也不是所讨论的代码的作用

我将用来完成概述的模拟的方案是拥有一个控制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 ]

使用互斥锁,可以通过包围checktliving的每个增量和减量来获得相同的结果。


注意,按照我的习惯使用全局变量并不是一个好习惯,我这样做只是为了简化多线程的演示,实际上,最好将它们包装在{{1}中},将整个模拟重构为namespace等。