Concurrency and Source Panels
Atomic Ticket Counter
Use an atomic counter when threads only need unique ticket numbers.
atomic
`fetch_add` updates the counter as one atomic operation and returns the previous value.
tickets
Each worker receives a different ticket without a separate mutex.
Atomic Ticket Counter
atomic_ticket_counter.cpp
Replay: real traced execution (multi-file project)
#include <atomic>
#include <iostream>
#include <thread>
void takeTicket(std::atomic<int>* nextTicket, int* ticket) {
*ticket = nextTicket->fetch_add(1);
}
int main() {
int start = 10;
std::atomic<int> nextTicket(start);
int firstTicket = 0;
int secondTicket = 0;
std::thread first(takeTicket, &nextTicket, &firstTicket);
std::thread second(takeTicket, &nextTicket, &secondTicket);
first.join();
second.join();
int issued = nextTicket.load() - start;
std::cout << "start=" << start << std::endl;
std::cout << "issued=" << issued << std::endl;
return 0;
}
#include <atomic>
#include <iostream>
#include <thread>
void takeTicket(std::atomic<int>* nextTicket, int* ticket) {
*ticket = nextTicket->fetch_add(1);
}
int main() {
int start = 1;
std::atomic<int> nextTicket(start);
int firstTicket = 0;
int secondTicket = 0;
std::thread first(takeTicket, &nextTicket, &firstTicket);
std::thread second(takeTicket, &nextTicket, &secondTicket);
first.join();
second.join();
int issued = nextTicket.load() - start;
std::cout << "start=" << start << std::endl;
std::cout << "issued=" << issued << std::endl;
return 0;
}
#include <atomic>
#include <iostream>
#include <thread>
void takeTicket(std::atomic<int>* nextTicket, int* ticket) {
*ticket = nextTicket->fetch_add(1);
}
int main() {
int start = 20;
std::atomic<int> nextTicket(start);
int firstTicket = 0;
int secondTicket = 0;
std::thread first(takeTicket, &nextTicket, &firstTicket);
std::thread second(takeTicket, &nextTicket, &secondTicket);
first.join();
second.join();
int issued = nextTicket.load() - start;
std::cout << "start=" << start << std::endl;
std::cout << "issued=" << issued << std::endl;
return 0;
}
start ← 10, nextTicket ← 10, firstTicket ← 0, secondTicket ← 0
9int main() {10 int start→ 10 = 10; //@start=1, 2011 std::atomic<int> nextTicket→ 10(start10);12 int firstTicket→ 0 = 0;13 int secondTicket→ 0 = 0;1415 std::thread first→ (empty)(takeTicket1, &nextTicket, &firstTicket);16 std::thread second→ (empty)(takeTicket1, &nextTicket, &secondTicket);1718 first(empty).join();19 second.join();void takeTicket(std::atomic<int>* nextTicket, int* ticket)
pass 1 of 25void takeTicket(std::atomic<int>* nextTicket⟨addr A⟩, int* ticket⟨addr B⟩) {6 *ticket⟨addr B⟩ = nextTicket⟨addr A⟩->fetch_add(1);7}void takeTicket(std::atomic<int>* nextTicket, int* ticket)
pass 2 of 25void takeTicket(std::atomic<int>* nextTicket⟨addr A⟩, int* ticket⟨addr C⟩) {6 *ticket⟨addr C⟩ = nextTicket⟨addr A⟩->fetch_add(1);7}issued ← 2
18 first(empty).join();19 second(empty).join();2021 int issued→ 2 = nextTicket12.load() - start10;22 std::cout << "start=" << start10 << std::endl;23 std::cout << "issued=" << issued2 << std::endl;24 return 0;25}outputstart=10 issued=2
start ← 1, nextTicket ← 1, firstTicket ← 0, secondTicket ← 0, first ← (empty)
9int main() {10 int start→ 1 = 1;11 std::atomic<int> nextTicket→ 1(start1);12 int firstTicket→ 0 = 0;13 int secondTicket→ 0 = 0;1415 std::thread first→ (empty)(takeTicket1, &nextTicket, &firstTicket);16 std::thread second(takeTicket1, &nextTicket, &secondTicket);void takeTicket(std::atomic<int>* nextTicket, int* ticket)
pass 1 of 25void takeTicket(std::atomic<int>* nextTicket⟨addr A⟩, int* ticket⟨addr B⟩) {6 *ticket⟨addr B⟩ = nextTicket⟨addr A⟩->fetch_add(1);7}void takeTicket(std::atomic<int>* nextTicket, int* ticket)
pass 2 of 25void takeTicket(std::atomic<int>* nextTicket⟨addr A⟩, int* ticket⟨addr C⟩) {6 *ticket⟨addr C⟩ = nextTicket⟨addr A⟩->fetch_add(1);7}second ← (empty), issued ← 2
15 std::thread first(takeTicket, &nextTicket, &firstTicket);16 std::thread second→ (empty)(takeTicket1, &nextTicket, &secondTicket);1718 first(empty).join();19 second(empty).join();2021 int issued→ 2 = nextTicket3.load() - start1;22 std::cout << "start=" << start1 << std::endl;23 std::cout << "issued=" << issued2 << std::endl;24 return 0;25}outputstart=1 issued=2
start ← 20, nextTicket ← 20, firstTicket ← 0, secondTicket ← 0
9int main() {10 int start→ 20 = 20;11 std::atomic<int> nextTicket→ 20(start20);12 int firstTicket→ 0 = 0;13 int secondTicket→ 0 = 0;1415 std::thread first→ (empty)(takeTicket1, &nextTicket, &firstTicket);16 std::thread second(takeTicket1, &nextTicket, &secondTicket);void takeTicket(std::atomic<int>* nextTicket, int* ticket)
pass 1 of 25void takeTicket(std::atomic<int>* nextTicket⟨addr A⟩, int* ticket⟨addr B⟩) {6 *ticket⟨addr B⟩ = nextTicket⟨addr A⟩->fetch_add(1);7}second ← (empty)
15std::thread first(takeTicket, &nextTicket, &firstTicket);16std::thread second→ (empty)(takeTicket1, &nextTicket, &secondTicket);1718first(empty).join();19second(empty).join();void takeTicket(std::atomic<int>* nextTicket, int* ticket)
pass 2 of 25void takeTicket(std::atomic<int>* nextTicket⟨addr A⟩, int* ticket⟨addr C⟩) {6 *ticket⟨addr C⟩ = nextTicket⟨addr A⟩->fetch_add(1);7}issued ← 2
18 first.join();19 second(empty).join();2021 int issued→ 2 = nextTicket22.load() - start20;22 std::cout << "start=" << start20 << std::endl;23 std::cout << "issued=" << issued2 << std::endl;24 return 0;25}outputstart=20 issued=2