-2

I want to test a scenario where I check weak_ptr for validity and return shared_ptr. between checking and returning if some other thread delete the shared_ptr we would face exception. I tried to simulate same scenario using windows sleep or cout but it seems to be not working. code is as follows:

#include <iostream>
#include <thread>
#include <windows.h>
#include <mutex>

using namespace std;

mutex m;

struct Block
{
    int * p_ = nullptr;
    Block() { p_ = new int[10000]; refCount_++; }


    ~Block() { delete[] p_; _p = nullptr; }

    int refCount_;
};

struct Weak_ptr
{
    Block * p_ = nullptr;
    Weak_ptr() { p_ = new Block(); }
    void Addref() { p_->refCount_++; }
    void release() { delete[] p_; p_ = nullptr; cout << "\nptr deleted\n"; }
};

void funct1(int x, Weak_ptr *ptr)
{
    cout << "\nin thread 1 \n";
    cout << "\nSleep thread 1\n";
    //Sleep(x)
    for (int i = 0; i < x; i++)
        cout << ".";
    cout << "\nAwake thread 1\n";
    ptr->release();
}

void funct2(int x, Weak_ptr *ptr)
{
    m.lock();
    cout << "\nin thread 2 \n";
    if (ptr->p_)
    {
        cout << "\nptr checked \n";
        //Sleep(x)
        for (int i = 0; i < x; i++)
            cout << "|";

        cout << "\nusing ptr in t2\n";
        ptr->Addref();
    }
    else
    {
        cout << "\ncheck succeeded \n";
    }
    m.unlock();
}

int main()
{
    Weak_ptr s;
    thread t1(&funct1, 2000, &s);
    thread t2(&funct2, 4000, &s);
    t1.join();
    t2.join();
}
Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
Ambarish
  • 63
  • 5
  • 3
    A mutex is not an unilateral deal. All threads accessing the resource need to use the same mutex. It's a cooperative thing. – n. m. could be an AI Jan 13 '20 at 06:14
  • Bug #1: The `refCount_` member on Block has an undefined value when the constructor completes. You need to explicitly initialize `refCount` to `1` instead of incrementing an undefined value. – selbie Jan 13 '20 at 06:30
  • Can you please post an output of your program? Does it fires an exception? – Steyrix Jan 13 '20 at 06:30
  • Bug #2: `Weak_ptr::release` just blindly deletes the underlying object regardless of the value of the `refCount_` member. I would expect it to decrement refCount, and then delete if it went to zero. – selbie Jan 13 '20 at 06:32
  • 2
    There are two smart pointer templates `std::shared_ptr` and `std::weak_ptr` which seem to do exactly what you're trying to achieve. Why don't you use those? Even if not, you could look at their implementations to find out how they solve your problems. – Ulrich Eckhardt Jan 13 '20 at 07:42
  • _"where I check weak_ptr"_ so you mean `Weak_ptr` or `std::weak_ptr`. _"and return shared_ptr"_ Do you mean `std::shared_ptr`? There are no STL smart pointers in your code. What is not working? – Thomas Sablik Jan 13 '20 at 14:25
  • This is just to simulate my std::weak_ptr, std::shared_ptr scenario. I haven't implemented this in my code. – Ambarish Jan 14 '20 at 05:03
  • The output is code fails in multithreading. Please check below answer by Athanasios Kataras. It perfectly answers my question. – Ambarish Jan 14 '20 at 05:04
  • Thomas Sablik, if some other thread deletes my memory (in case of std::shared_ptr, it goes out of scope) after checking (in case of std::shared_ptr we check shared_ptr.expired()) and before using ( in case of std::shared_ptr, statement std::weak_ptr.lock()). My expectation was not to have crash if I am using mutex (which was wrong see answer below). – Ambarish Jan 14 '20 at 05:10

1 Answers1

2

You must protect your code, wherever you are changing shared data.

Let me explain your situation with an example:

m.lock(); // what does that mean?
// do your business

Your mutex m is a WC door. If someone is already locking from the other side, then you can't go in. So when m.lock() is hit two things happen.

  1. Check if anyone is already behind the locked door
  2. Go through and lock the door

Now imagine another way that leads to the same WC but without a lock. Just a door with no security.

// No m.lock() here

Whether or not the other door is locked it doesn't matter, anyone can join the WC at any time (not cool).

Now imagine a third situation.

m2.lock();
// Do other stuff

Now you have another door but with another lock. So two people can access the door at the same time. In code analogy, if the muted reference is not the same, then the code is not safe.

Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61