Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Build Check

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
windows-build:
runs-on: windows-latest

strategy:
matrix:
build_type: [Debug, Release]

env:
VCPKG_MAX_CONCURRENCY: 8
VCPKG_ROOT: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\vcpkg"

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Visual Studio Developer Command Prompt
uses: microsoft/setup-msbuild@v2
with:
vs-version: '17.0'
msbuild-architecture: x64

- name: Cache vcpkg
uses: actions/cache@v4
with:
path: |
${{ github.workspace }}/build/vcpkg_installed
C:/Users/runneradmin/AppData/Local/vcpkg/archives
C:/Users/runneradmin/AppData/Local/vcpkg/registries

key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json') }}-${{ matrix.build_type }}
restore-keys: |
vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json') }}-
vcpkg-${{ runner.os }}-

- name: Configure CMake
run: |
cmake `
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} `
-DVCPKG_TARGET_TRIPLET=x64-windows `
-DVCPKG_USE_BINARY_PACKAGES=ON `
-B ${{ github.workspace }}/build

- name: Build Project
run: |
cmake --build ${{ github.workspace }}/build --config ${{ matrix.build_type }}

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: windows-build-${{ matrix.build_type }}
path: |
${{ github.workspace }}/build/**/*.exe
if-no-files-found: error

gcc-build:
runs-on: ubuntu-latest
container: ubuntu:jammy
strategy:
matrix:
build_type: [ Debug, Release ]
gcc_version: [ 13 ]
steps:
- uses: actions/checkout@v4

- name: Install Dependencies
run: |
apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
software-properties-common gpg-agent wget \
build-essential cmake libwxgtk3.0-gtk3-dev libwxgtk3.0-gtk3-0v5 \
libopencv-dev python3-opencv \
pkg-config
add-apt-repository ppa:ubuntu-toolchain-r/test
apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
g++-${{matrix.gcc_version}} gcc-${{matrix.gcc_version}}

- name: Setup GCC
run: |
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${{matrix.gcc_version}} 100
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${{matrix.gcc_version}} 100

- name: Build
run: |
cmake -B build -DCMAKE_BUILD_TYPE=${{matrix.build_type}}
cmake --build build --config ${{matrix.build_type}}
mkdir -p /github/workspace/artifacts
cp build/traffic_sim /github/workspace/artifacts/

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: linux-gcc${{matrix.gcc_version}}-${{matrix.build_type}}
path: /github/workspace/artifacts/traffic_sim
if-no-files-found: error
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
.github/**
.idea/**
36 changes: 27 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
cmake_minimum_required(VERSION 3.11.3)
set(CMAKE_CXX_STANDARD 17)

# set(CMAKE_CXX_STANDARD 17)
project(traffic_simulation)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -pthread")
# Set output directories to the build
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})

find_package(OpenCV 4.1 REQUIRED)
if(WIN32)
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -pthread")
endif()

project(traffic_sim)

if(DEFINED VCPKG_INSTALLED_DIR)
set(OpenCV_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/opencv4")
else()
message(WARNING "VCPKG_INSTALLED_DIR not defined. OpenCV_DIR might need to be set manually.")
endif()

# Find opencv4 dependency
find_package(OpenCV 4.1 REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
link_directories(${OpenCV_LIBRARY_DIRS})
add_definitions(${OpenCV_DEFINITIONS})

# Find all executables
file(GLOB project_SRCS src/*.cpp) #src/*.h
# Find sources
file(GLOB project_SRCS src/*.cpp)

# Create an executable
add_executable(traffic_sim ${project_SRCS})

# Add project executable
add_executable(traffic_simulation ${project_SRCS})
target_link_libraries(traffic_simulation ${OpenCV_LIBRARIES})
# Link libraries
target_link_libraries(traffic_sim ${OpenCV_LIBRARIES})
28 changes: 12 additions & 16 deletions src/Intersection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ std::vector<std::shared_ptr<Street>> Intersection::queryStreets(std::shared_ptr<
// adds a new vehicle to the queue and returns once the vehicle is allowed to enter
void Intersection::addVehicleToQueue(std::shared_ptr<Vehicle> vehicle)
{
std::unique_lock<std::mutex> lck(_mtx);
std::unique_lock<std::mutex> cout_lck(_cout_mtx);
std::cout << "Intersection #" << _id << "::addVehicleToQueue: thread id = " << std::this_thread::get_id() << std::endl;
lck.unlock();
cout_lck.unlock();

// add new vehicle to the end of the waiting line
std::promise<void> prmsVehicleAllowedToEnter;
Expand All @@ -83,12 +83,14 @@ void Intersection::addVehicleToQueue(std::shared_ptr<Vehicle> vehicle)

// wait until the vehicle is allowed to enter
ftrVehicleAllowedToEnter.wait();
lck.lock();
cout_lck.lock();
std::cout << "Intersection #" << _id << ": Vehicle #" << vehicle->getID() << " is granted entry." << std::endl;

// FP.6b : use the methods TrafficLight::getCurrentPhase and TrafficLight::waitForGreen to block the execution until the traffic light turns green.
cout_lck.unlock();

lck.unlock();
// FP.6b : use the methods TrafficLight::getCurrentPhase and TrafficLight::waitForGreen to block the execution until the traffic light turns green.
_trafficLight.waitForGreen();
cout_lck.lock();
std::cout << "Intersection #" << _id << ": Vehicle #" << vehicle->getID() << " got a green light." << '\n';
}

void Intersection::vehicleHasLeft(std::shared_ptr<Vehicle> vehicle)
Expand All @@ -109,9 +111,10 @@ void Intersection::setIsBlocked(bool isBlocked)
void Intersection::simulate() // using threads + promises/futures + exceptions
{
// FP.6a : In Intersection.h, add a private member _trafficLight of type TrafficLight. At this position, start the simulation of _trafficLight.

_trafficLight.simulate();

// launch vehicle queue processing in a thread
threads.emplace_back(std::thread(&Intersection::processVehicleQueue, this));
threads.emplace_back(&Intersection::processVehicleQueue, this);
}

void Intersection::processVehicleQueue()
Expand Down Expand Up @@ -140,12 +143,5 @@ void Intersection::processVehicleQueue()
bool Intersection::trafficLightIsGreen()
{
// please include this part once you have solved the final project tasks
/*
if (_trafficLight.getCurrentPhase() == TrafficLightPhase::green)
return true;
else
return false;
*/

return true; // makes traffic light permanently green
return _trafficLight.getCurrentPhase() == TrafficLightPhase::green;
}
8 changes: 5 additions & 3 deletions src/Intersection.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#ifndef INTERSECTION_H
#define INTERSECTION_H

#include <vector>
#include "TrafficLight.h"
#include <future>
#include <mutex>
#include <memory>
#include "TrafficObject.h"
#include <mutex>
#include <vector>

// forward declarations to avoid include cycle
class Street;
Expand Down Expand Up @@ -54,6 +54,8 @@ class Intersection : public TrafficObject
std::vector<std::shared_ptr<Street>> _streets; // list of all streets connected to this intersection
WaitingVehicles _waitingVehicles; // list of all vehicles and their associated promises waiting to enter the intersection
bool _isBlocked; // flag indicating wether the intersection is blocked by a vehicle

TrafficLight _trafficLight;
};

#endif
1 change: 1 addition & 0 deletions src/Street.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define STREET_H

#include "TrafficObject.h"
#include <memory>

// forward declaration to avoid include cycle
class Intersection;
Expand Down
52 changes: 41 additions & 11 deletions src/TrafficLight.cpp
Original file line number Diff line number Diff line change
@@ -1,58 +1,88 @@
#include <iostream>
#include <random>
#include "TrafficLight.h"

using namespace std::chrono;
using namespace std::chrono_literals;

/* Implementation of class "MessageQueue" */

/*
template <typename T>
T MessageQueue<T>::receive()
{
// FP.5a : The method receive should use std::unique_lock<std::mutex> and _condition.wait()
// to wait for and receive new messages and pull them from the queue using move semantics.
// The received object should then be returned by the receive function.
// The received object should then be returned by the receive function.
std::unique_lock<std::mutex> queue_lck(_queue_mtx);
_queue_cv.wait(queue_lck, [this] { return !_queue.empty(); });
T message = std::move(_queue.front());
_queue.pop_front();

return message;
}

template <typename T>
void MessageQueue<T>::send(T &&msg)
{
// FP.4a : The method send should use the mechanisms std::lock_guard<std::mutex>
// as well as _condition.notify_one() to add a new message to the queue and afterwards send a notification.
std::unique_lock<std::mutex> queue_lck(_queue_mtx);
_queue.push_back(std::move(msg));
_queue_cv.notify_one();
}
*/

/* Implementation of class "TrafficLight" */

/*
TrafficLight::TrafficLight()
{
// the thread should not be running, no synchronization needed
_currentPhase = TrafficLightPhase::red;
}

void TrafficLight::waitForGreen()
{
// return if already green
if (getCurrentPhase() == TrafficLightPhase::green) {
return;
}

// FP.5b : add the implementation of the method waitForGreen, in which an infinite while-loop
// runs and repeatedly calls the receive function on the message queue.
// Once it receives TrafficLightPhase::green, the method returns.
while (_messages.receive() != TrafficLightPhase::green) {
std::this_thread::yield();
}
}

TrafficLightPhase TrafficLight::getCurrentPhase()
{
std::lock_guard<std::mutex> lock(_currentPhase_mtx); // read is synchronized
return _currentPhase;
}

void TrafficLight::simulate()
{
// FP.2b : Finally, the private method „cycleThroughPhases“ should be started in a thread when the public method „simulate“ is called. To do this, use the thread queue in the base class.
threads.emplace_back(&TrafficLight::cycleThroughPhases, this);
}

void TrafficLight::toggleCurrentPhase() {
_currentPhase = _currentPhase == TrafficLightPhase::red ? TrafficLightPhase::green : TrafficLightPhase::red;
_messages.send(std::move(_currentPhase));
}

// virtual function which is executed in a thread
void TrafficLight::cycleThroughPhases()
{
void TrafficLight::cycleThroughPhases() {
// FP.2a : Implement the function with an infinite loop that measures the time between two loop cycles
// and toggles the current phase of the traffic light between red and green and sends an update method
// to the message queue using move semantics. The cycle duration should be a random value between 4 and 6 seconds.
// Also, the while-loop should use std::this_thread::sleep_for to wait 1ms between two cycles.
}
// Also, the while-loop should use std::this_thread::sleep_for to wait 1ms between two cycles.
auto next(high_resolution_clock::now() + seconds(_dis(_gen)));

for (time_point<high_resolution_clock> now = high_resolution_clock::now();;now = high_resolution_clock::now()) {
if (now > next) {
toggleCurrentPhase();
next = now + seconds(_dis(_gen));
}

*/
std::this_thread::sleep_for(milliseconds(1));
}
}
Loading