Create and use threads in C ++

advertisements

For University I have to write a program like space Invaders.

Now we have to write the "bullet" - Class for the main spaceShip, to shoot bullets. Every bullet has to create its own thread. The thread has to execute the run method.

Bullet.hpp

ifndef BULLET_HPP_
define BULLET_HPP_

include "TriangleMesh.hpp"

include <GL/glu.h>
include <GL/glut.h>

include <thread>
include <chrono>

namespace asteroids
{
    class Bullet : public TriangleMesh
    {
        public:
        /**
         * @brief Contructor. Build a bullet on the given Fighter's
         *                      position. The bullet will move on the
         *                      given axis.
         * @param   fighter_position   Position of the fighter that shoots this bullet
         * @param   fighter_axis   Axis the bullet will move on
         */
        Bullet(Vertex<float> fighter_position, Vertex<float> fighter_axis);
        ~Bullet();
        /**
         * @brief Moves the bullet until it's lifetime is over.
         */
        void run();
        /**
         * @brief Starts bullet movement
         */
        void start();
        /*
         * @brief Stops bullet movement
         */
        void stop();
        /**
         * @brief Renders the bullet via glutSolidSphere.
         */
        void render();
        /**
         * @brief Returns the status of this bullet.
         * @return false, if the bullet's lifetime is over and true otherwise
         */
        bool isAlive();
        private:
        // Lifetime, i.e., how many timesteps the bullet visible
        static const int m_lifetime = 9000;
        // True, if the bullet's lifetime isn't over yet
        bool m_alive;
        // Flight direction of the bullet
        Vertex<float> m_fighterAxis;
        //position of the fighter
        Vertex<float> m_fighterPosition;
        static void staticRun(Bullet * bullet);
        bool isRunning;
        /// TODO: ADD TIMING AND THREAD FUNCTIONALITY
        void stopThread();
        void startThread();
        void sleep(int n)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(n));
        }
    };
} // namespace asteroids

#endif /* BULLET_HPP_ */

/**
* Bullet.cpp
*
*/

BULLET.CPP

#include "Bullet.hpp"
using namespace std;

namespace asteroids
{
    Bullet::Bullet(Vertex<float> fighter_position, Vertex<float> fighter_axis)
        : m_alive(true)
    {
        // TODO: Implement Ctor logic
        m_fighterAxis = fighter_axis;
        m_fighterPosition = fighter_position;
        m_position = fighter_position;
        startThread();
    }
    void Bullet::stopThread()
    {
        currentThread->join();
    }
    //creates a static-member option for starting the thread with an argument.
    void Bullet::staticRun(Bullet* bullet)
    {
        bullet->run();
    }
    //Logic to create and start a Thread with out static function to execute
    void Bullet::startThread()
    {
        Bullet* bullet = this;
        std::thread t1(&Bullet::staticRun, bullet);
        currentThread = t1; //Here i wanted to set the pointer equal the existing thread
        //But compiler says that i cant convert a thread type to a                           //pointer type
    }

    Bullet::~Bullet() {}
    bool Bullet::isAlive()
    {
        return m_alive;
    }

    void Bullet::stop()
    {
        m_alive = false;
    }

    void Bullet::start()
    {
        if (isAlive())
        {
            // TODO: Implement thread start logic
            startThread();
        }
    }

    void Bullet::run()
    {
        Vertex<float> move = Vertex<float>(1, 1, 1);
        for (int i = 0; i < m_lifetime; i++)
        {
            m_position = m_fighterAxis + move;
            render();
            sleep(1000);
            //this->sleep(1000);
        }
        stop();
    }

    void Bullet::render()
    {
        // Compute transformation matrix
        computeMatrix();
        // Push old transformation of the OpenGL matrix stack and
        // start rendering the bullet in according to the
        // internal transformation matrix
        glPushMatrix();
        glMultMatrixf(m_transformation);
        glutSolidSphere(10, 16, 16);
        // Pop transformation matrix of this object
        // to restore the previous state of the OpenGL
        // matrix stack
        glPopMatrix();
    }
} // namespace asreroids

Now my question is: is it the right way to create the thread in a separate method and create a pointer which holds it?

Or how would you implement a thread-logic without a thread-parent-class?

Thank you for help guys, and excuse me if the layout is not the right way to post a commend here, its my first post ever ^^


You should bind the function to the variable that you're trying to pass, in this case I suggest you to bind it to the instance that you're creating and then the arguments that the function will receive, usually you declare the function as a member function and then bind the instance to it, then pass it to the thread that you're creating.

We're using mutex below in order to protect the running boolean from multiple thread access. You should use a mutex to protect the variables that could be accessed by multiple threads.

currentThread.join(); awaits for the thread to finish.

#include <thread>
#include <mutex>
#include <chrono>

class Bullet{

public:
    void startThread(){
        currentThread = std::thread(std::bind(&Bullet::run, this));
    }

    void run(){
        while (isRunning()){
            std::this_thread::sleep_for(std::chrono::milliseconds(200));

            //Do something.
        }
    }

    void Bullet::stopThread()
    {
        runMutex.lock();
        running = false;
        runMutex.unlock();

        currentThread.join();
    }

    bool isRunning(){
        bool isRunning = false;
        runMutex.lock();
        isRunning = running;
        runMutex.unlock();
        return isRunning;
    }

private:
    std::thread currentThread;
    std::mutex runMutex;
    bool running;
};

int main()
{

    Bullet bullet;
    bullet.startThread();

    bullet.stopThread();

    return 0; //return.
}