Accessing and working with std::vector from multiple threads ...

Hello,

I have a vector that I would like to access and work with from multiple threads. I have created an example below to illustrate the functionality that I would like to accomplish.

The goals are to be (1) high speed, (2) thread safe, and (3) *if possible* continue to use vectors as my larger project uses vectors all over the place and as such I would like to maintain that.

However, if I need to switch from vectors to something else then I am open to that as well.

The following example below compiles but crashes rather quickly because it is not thread safe.

Any ideas on how I can fix the example below which I can then apply to my larger project?

Thank you:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

#include <string>
#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 (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;

}
Last edited on
You need to put a mutex around access to the vector. See http://www.cplusplus.com/reference/mutex/mutex/.

Topic archived. No new replies allowed.