2014-10-20 32 views
0

我有一個我想從多個線程訪問和使用的向量。我在下面創建了一個示例來說明我想完成的功能。從多個線程訪問和使用std :: vector

目標是(1)高速度,(2)線程安全,和(3)如果可能的話繼續使用向量,因爲我的大型項目使用矢量遍佈整個地方,因此我想保持這一點。

但是,如果我需要從矢量切換到其他東西,那麼我對此也是開放的。

下面的例子編譯但相當快速崩潰,因爲它不是線程安全的。

關於如何修復以下示例的任何想法,我可以將其應用於我的大型項目?

謝謝:

#include <vector> 
#include <ctime> 
#include <thread> 
#include <iostream> 
#include <random> 
#include <atomic> 
#include <algorithm> 

enum EmployeeType { 

    HOURLY = 0, 
    SALARIED = 1, 
    COMMISSION = 2, 
    OTHER = 3 

}; 

enum EmployeePosition { 

    SalesPerson = 0, 
    Cashier = 1, 
    Stocker = 2, 
    Janitor = 3, 
    AssistantManager = 4, 
    Manager = 5, 
    GeneralManager = 6, 
    Owner = 7 

}; 

class Employee; 

class Employee { 

private: 

    float _TotalCostPerYear; 
    EmployeeType _TypeOfEmployee; 
    EmployeePosition _PositionOfEmployee; 

protected: 

public: 

    Employee() :_TotalCostPerYear(0.0f), _TypeOfEmployee(EmployeeType::HOURLY), 
     _PositionOfEmployee(EmployeePosition::SalesPerson){}; 

    float GetTotalCost() { return _TotalCostPerYear; } 
    void SetTotalCost(float ValueToSet) { _TotalCostPerYear = ValueToSet; } 

    EmployeeType GetEmployeeType() { return _TypeOfEmployee; } 
    void SetEmployeeType(EmployeeType ValueToSet) { _TypeOfEmployee = ValueToSet; } 

    EmployeePosition GetEmployeePosition() { return _PositionOfEmployee; } 
    void SetEmployeePosition(EmployeePosition ValueToSet) { _PositionOfEmployee = ValueToSet; } 

}; 

std::vector <Employee> AllEmployees; 

std::thread* AddEmployeesThread; 
std::thread* RemoveEmployeesThread; 
std::thread* CalculateEmploymentCostsThread; 
std::thread* PrintTotalsThread; 

std::atomic<bool> ContinueProcessing = true; 
std::atomic<float> TotalSalaryCosts = 0.0f; 

std::uniform_int_distribution<int>* RandDistTypeOfEmployee; 
std::uniform_int_distribution<int>* RandDistPositionOfEmployee; 
std::uniform_real_distribution<float>* RandDistSalaryOfEmployee; 

std::mt19937* RandomNumberGenerator; 

time_t rawtime; 
struct tm timeinfo; 

void RandomAddEmployees(); 
void RandomRemoveEmployees(); 
void CalculateEmployementCosts(); 
void PrintTotals(); 

void RandomAddEmployees() { 

    while (ContinueProcessing) { 

     Employee NewEmployee; 

     NewEmployee.SetEmployeePosition((EmployeePosition)(*RandDistPositionOfEmployee)(*RandomNumberGenerator)); 
     NewEmployee.SetEmployeeType((EmployeeType)(*RandDistTypeOfEmployee)(*RandomNumberGenerator)); 
     NewEmployee.SetTotalCost((*RandDistSalaryOfEmployee)(*RandomNumberGenerator)); 

     AllEmployees.push_back(NewEmployee); 

    } 

} 

void RandomRemoveEmployees() { 

    while (ContinueProcessing) { 

     EmployeePosition PositionToRemove = (EmployeePosition)(*RandDistPositionOfEmployee)(*RandomNumberGenerator); 

     static const auto is_position_erasable = [&PositionToRemove](Employee& E) { return E.GetEmployeePosition() == PositionToRemove; }; 

     AllEmployees.erase(std::remove_if(AllEmployees.begin(), AllEmployees.end(), is_position_erasable), AllEmployees.end()); 

     EmployeeType TypeToRemove = (EmployeeType)(*RandDistTypeOfEmployee)(*RandomNumberGenerator); 

     static const auto is_type_erasable = [&TypeToRemove](Employee& E) { return E.GetEmployeeType() == TypeToRemove; }; 

     AllEmployees.erase(std::remove_if(AllEmployees.begin(), AllEmployees.end(), is_position_erasable), AllEmployees.end()); 

    } 

} 

void CalculateEmployementCosts() { 

    while (ContinueProcessing) { 

     float RunningTotal = 0.0f; 

     for (unsigned int i = 0; i < AllEmployees.size(); ++i) { 

      RunningTotal += AllEmployees[i].GetTotalCost(); 

     } 

     TotalSalaryCosts = RunningTotal; 

    } 

} 

void PrintTotals() { 

    while (ContinueProcessing) { 

     time(&rawtime); 
     localtime_s(&timeinfo, &rawtime); 

     if ((timeinfo.tm_sec % 5) == 0) { 

      std::cout << "\n\nIn total there are " << AllEmployees.size() << " employees with a total cost of " << TotalSalaryCosts << " to the company."; 

     } 

    } 

} 


int main(int argc, char** argv) { 

    time(&rawtime); 
    localtime_s(&timeinfo, &rawtime); 

    RandomNumberGenerator = new std::mt19937((unsigned int)timeinfo.tm_sec); 
    RandDistTypeOfEmployee = new std::uniform_int_distribution<int>(0, 3); 
    RandDistPositionOfEmployee = new std::uniform_int_distribution<int>(0, 7); 
    RandDistSalaryOfEmployee = new std::uniform_real_distribution<float>(35000.0f, 300000.0f); 

    std::cout << "Welcome to the crude employment simulation program. Press enter to get started."; 
    std::cout << "\n\nNote that once the program starts you can press any key to stop the simulation.\n"; 

    std::cin.get(); 

    AddEmployeesThread = new std::thread(RandomAddEmployees); 
    RemoveEmployeesThread = new std::thread(RandomRemoveEmployees); 
    CalculateEmploymentCostsThread = new std::thread(CalculateEmployementCosts); 
    PrintTotalsThread = new std::thread(PrintTotals); 

    std::cin.get(); 

    std::cout << "\n\nExiting the simulation."; 

    ContinueProcessing = false; 

    AddEmployeesThread->join(); 
    RemoveEmployeesThread->join(); 
    CalculateEmploymentCostsThread->join(); 
    PrintTotalsThread->join(); 

    delete AddEmployeesThread; 
    delete RemoveEmployeesThread; 
    delete CalculateEmploymentCostsThread; 
    delete PrintTotalsThread; 

    delete RandDistSalaryOfEmployee; 
    delete RandDistPositionOfEmployee; 
    delete RandDistTypeOfEmployee; 

} 
+0

你真的需要所有'新'嗎? – 2014-10-20 01:50:29

+0

@NeilKirk可能不是;這是一個例子,我習慣於這樣使用C++。我可以把它們放到我的變量聲明部分,它應該可以工作。 – user3434662 2014-10-20 04:25:18

回答

2

您需要保護訪問您AllEmployees變量,以便只有一個線程可以在任何時候訪問它。您可以使用std::mutex進行保護,並在必要時使用std::lock_guard<std::mutex>進行鎖定。首先,添加此包含文件:

#include <mutex> 

接下來,定義一個互斥—您可以添加正上方的AllEmployees變量的定義如下:

std::mutex AllEmpMtx; 

然後,在訪問或修改AllEmployees的所有功能,任何這樣的操作之前鎖定該互斥,像這樣:

std::lock_guard<std::mutex> lock(AllEmpMtx); 

例如,在RandomAddEmployees功能,您應該在撥打AllEmployees.push_back(NewEmployee)的電話上方添加lock_guard

std::lock_guard<std::mutex>實例超出作用域時,其析構函數將解鎖互斥量。

順便說一句,你似乎使用範圍枚舉爲EmployeeTypeEmployeePosition。 C++ 11標準要求使用enum class來定義它們,而不僅僅是enum

+0

正是我需要的!謝謝。 – user3434662 2014-10-20 01:15:55