}
 
+chip::chip(const ::std::weak_ptr<::gpiod_chip>& chip_ptr)
+       : _m_chip(chip_ptr)
+{
+
+}
+
 void chip::open(const ::std::string& device, int how)
 {
        auto func = open_funcs.at(how);
 
                return EXIT_FAILURE;
        }
 
-       ::gpiod::line line = ::gpiod::find_line(argv[1]);
-       if (!line)
+       auto ret = ::gpiod::find_line(argv[1]);
+       if (!ret.first)
                return EXIT_FAILURE;
 
-       ::std::cout << line.get_chip().name() << " " << line.offset() << ::std::endl;
+       ::std::cout << ret.second.name() << " " << ret.first.offset() << ::std::endl;
 
        return EXIT_SUCCESS;
 }
 
 private:
 
        chip(::gpiod_chip* chip);
+       chip(const ::std::weak_ptr<::gpiod_chip>& chip_ptr);
 
        void throw_if_noref(void) const;
 
        ::std::shared_ptr<::gpiod_chip> _m_chip;
 
+       friend line;
        friend chip_iter;
        friend line_iter;
 };
        GPIOD_API int event_get_fd(void) const;
 
        /**
-        * @brief Get the reference to the parent chip.
-        * @return Reference to the parent chip object.
+        * @brief Get the parent chip.
+        * @return Parent chip of this line.
         */
-       GPIOD_API const chip& get_chip(void) const;
+       GPIOD_API const chip get_chip(void) const;
 
        /**
         * @brief Re-read the line info from the kernel.
        line_event make_line_event(const ::gpiod_line_event& event) const noexcept;
 
        ::gpiod_line* _m_line;
-       chip _m_chip;
+       ::std::weak_ptr<::gpiod_chip> _m_owner;
+
+       class chip_guard
+       {
+       public:
+               chip_guard(const line& line);
+               ~chip_guard(void) = default;
+
+               chip_guard(const chip_guard& other) = delete;
+               chip_guard(chip_guard&& other) = delete;
+               chip_guard& operator=(const chip_guard&& other) = delete;
+               chip_guard& operator=(chip_guard&& other) = delete;
+
+       private:
+               ::std::shared_ptr<::gpiod_chip> _m_chip;
+       };
 
        friend chip;
        friend line_bulk;
 /**
  * @brief Find a GPIO line by name. Search all GPIO chips present on the system.
  * @param name Name of the line.
- * @return Returns a line object - empty if the line was not found.
+ * @return Returns a <line, chip> pair where line is the line with given name
+ *         and chip is the line's owner. Both objects are empty if the line was
+ *         not found.
  */
-GPIOD_API line find_line(const ::std::string& name);
+GPIOD_API ::std::pair<line, chip> find_line(const ::std::string& name);
 
 /**
  * @brief Describes a single GPIO line event.
 
 {
        ::gpiod_line* next = ::gpiod_line_iter_next(this->_m_iter.get());
 
-       this->_m_current = next ? line(next, this->_m_current._m_chip) : line();
+       this->_m_current = next ? line(next, this->_m_current._m_owner) : line();
 
        return *this;
 }
 
 
 line::line(void)
        : _m_line(nullptr),
-         _m_chip()
+         _m_owner()
 {
 
 }
 
 line::line(::gpiod_line* line, const chip& owner)
        : _m_line(line),
-         _m_chip(owner)
+         _m_owner(owner._m_chip)
 {
 
 }
 unsigned int line::offset(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        return ::gpiod_line_offset(this->_m_line);
 }
 ::std::string line::name(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        const char* name = ::gpiod_line_name(this->_m_line);
 
 ::std::string line::consumer(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        const char* consumer = ::gpiod_line_consumer(this->_m_line);
 
 int line::direction(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        int dir = ::gpiod_line_direction(this->_m_line);
 
 int line::active_state(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        int active = ::gpiod_line_active_state(this->_m_line);
 
 int line::bias(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        return bias_mapping.at(::gpiod_line_bias(this->_m_line));
 }
 bool line::is_used(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        return ::gpiod_line_is_used(this->_m_line);
 }
 bool line::is_open_drain(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        return ::gpiod_line_is_open_drain(this->_m_line);
 }
 bool line::is_open_source(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        return ::gpiod_line_is_open_source(this->_m_line);
 }
 bool line::is_requested(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        return ::gpiod_line_is_requested(this->_m_line);
 }
 line_event line::event_read(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        ::gpiod_line_event event_buf;
        line_event event;
 ::std::vector<line_event> line::event_read_multiple(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        /* 16 is the maximum number of events stored in the kernel FIFO. */
        ::std::array<::gpiod_line_event, 16> event_buf;
 int line::event_get_fd(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        int ret = ::gpiod_line_event_get_fd(this->_m_line);
 
        return ret;
 }
 
-const chip& line::get_chip(void) const
+const chip line::get_chip(void) const
 {
-       return this->_m_chip;
+       return chip(this->_m_owner);
 }
 
 void line::update(void) const
 {
        this->throw_if_null();
+       line::chip_guard lock_chip(*this);
 
        int ret = ::gpiod_line_update(this->_m_line);
 
 void line::reset(void)
 {
        this->_m_line = nullptr;
-       this->_m_chip.reset();
+       this->_m_owner.reset();
 }
 
 bool line::operator==(const line& rhs) const noexcept
                throw ::std::logic_error("object not holding a GPIO line handle");
 }
 
-line find_line(const ::std::string& name)
+line::chip_guard::chip_guard(const line& line)
+       : _m_chip(line._m_owner)
 {
-       line ret;
+       
+}
+
+::std::pair<line, chip> find_line(const ::std::string& name)
+{
+       ::std::pair<line, chip> ret;
 
        for (auto& it: make_chip_iter()) {
-               ret = it.find_line(name);
-               if (ret)
+               ret.first = it.find_line(name);
+               if (ret.first) {
+                       ret.second = it;
                        break;
+               }
        }
 
        return ret;
 
 void line_bulk::request(const line_request& config, const ::std::vector<int> default_vals) const
 {
        this->throw_if_empty();
+       line::chip_guard lock_chip(this->_m_bulk.front());
 
        if (!default_vals.empty() && this->size() != default_vals.size())
                throw ::std::invalid_argument("the number of default values must correspond with the number of lines");
 void line_bulk::release(void) const
 {
        this->throw_if_empty();
+       line::chip_guard lock_chip(this->_m_bulk.front());
 
        ::gpiod_line_bulk bulk;
 
 ::std::vector<int> line_bulk::get_values(void) const
 {
        this->throw_if_empty();
+       line::chip_guard lock_chip(this->_m_bulk.front());
 
        ::std::vector<int> values;
        ::gpiod_line_bulk bulk;
 void line_bulk::set_values(const ::std::vector<int>& values) const
 {
        this->throw_if_empty();
+       line::chip_guard lock_chip(this->_m_bulk.front());
 
        if (values.size() != this->_m_bulk.size())
                throw ::std::invalid_argument("the size of values array must correspond with the number of lines");
                           const ::std::vector<int> values) const
 {
        this->throw_if_empty();
+       line::chip_guard lock_chip(this->_m_bulk.front());
 
        if (!values.empty() && this->_m_bulk.size() != values.size())
                throw ::std::invalid_argument("the number of default values must correspond with the number of lines");
 void line_bulk::set_flags(::std::bitset<32> flags) const
 {
        this->throw_if_empty();
+       line::chip_guard lock_chip(this->_m_bulk.front());
 
        ::gpiod_line_bulk bulk;
        int rv, gflags;
 void line_bulk::set_direction_input() const
 {
        this->throw_if_empty();
+       line::chip_guard lock_chip(this->_m_bulk.front());
 
        ::gpiod_line_bulk bulk;
        int rv;
 void line_bulk::set_direction_output(const ::std::vector<int>& values) const
 {
        this->throw_if_empty();
+       line::chip_guard lock_chip(this->_m_bulk.front());
 
        if (values.size() != this->_m_bulk.size())
                throw ::std::invalid_argument("the size of values array must correspond with the number of lines");
 line_bulk line_bulk::event_wait(const ::std::chrono::nanoseconds& timeout) const
 {
        this->throw_if_empty();
+       line::chip_guard lock_chip(this->_m_bulk.front());
 
        ::gpiod_line_bulk bulk, event_bulk;
        ::timespec ts;
 
 
        SECTION("line found")
        {
-               auto line = ::gpiod::find_line("gpio-mockup-C-5");
-               REQUIRE(line.offset() == 5);
-               REQUIRE(line.name() == "gpio-mockup-C-5");
-               REQUIRE(line.get_chip().label() == "gpio-mockup-C");
+               auto ret = ::gpiod::find_line("gpio-mockup-C-5");
+               REQUIRE(ret.first.offset() == 5);
+               REQUIRE(ret.first.name() == "gpio-mockup-C-5");
+               REQUIRE(ret.second.label() == "gpio-mockup-C");
        }
 
        SECTION("line not found")
        {
-               auto line = ::gpiod::find_line("nonexistent-line");
-               REQUIRE_FALSE(line);
+               auto ret = ::gpiod::find_line("nonexistent-line");
+               REQUIRE_FALSE(ret.first);
        }
 }