Interwoven threads affecting linked list - c++

I am told that the code in insert() isn't thread-safe because an interwoven thread can set head to node after another thread does, effectively loosing a link to one node. But no matter how many times I run this program I keep getting 2 as the number of nodes instead of 1. Why is that?
#include <functional>
#include <iostream>
#include <thread>
#include <chrono>
struct List
{
struct Node
{
int data{0};
Node* next{0};
};
Node* head{0};
void insert(int n)
{
Node* node = new Node{n};
node->next = head;
head = node;
}
};
int Count(List& list)
{
int count = 0;
for (List::Node* head = list.head; head != nullptr; head = head->next)
count++;
return count;
}
int main()
{
List i;
std::thread t1(&List::insert, &i, 5);
std::thread t2(&List::insert, &i, 3);
t1.join();
t2.join();
std::cout << Count(i);
}
Demo

Related

How would you write a function to create a linked list?

I was wondering if it would be possible to create a function that would create a linked list, here is my attempt, I would appreciate if anyone could tell me if this is correct or not.
The logic is as follows:
Take in a starting node, the created linked list will be connected to this node
Create all the nodes that need to be created and store their memory addresses in a vector
Loop through the vector linking together all of the nodes
#include <iostream>
#include <vector>
using namespace std;
class node{
public:;
int value;
node *next;
node():value(0),next(NULL){};
};
void CreateList(node& starting_node, int number_of_nodes_to_create){
// Keep track of all the nodes addresses that need to be created
vector <node*> nodes = {};
// Create the nodes
for (int i = 0; i < number_of_nodes_to_create;i++){
node *temp = new node;
nodes.push_back(temp);
}
// Attach the first created node to the starting node
starting_node.next = nodes[0];
// We now have all the new nodes, now we just need to link them all up with pointers
for (int i = 0; i < nodes.size()-1;i++){
nodes[i] ->next = nodes[i+1];
}
}
I am very much a beginner, all criticism is welcome!
You don't need the vector at all. Your function can be simplified to something like this:
#include <iostream>
#include <vector>
using namespace std;
class node{
public:
int value;
node *next;
node() : value(0), next(NULL) {}
};
void CreateList(node* &starting_node, int number_of_nodes_to_create){
// if the list already exists, find the end of it...
node **n = &starting_node;
while (*n) {
n = &((*n)->next);
}
// Create the nodes
while (number_of_nodes_to_create > 0) {
*n = new node;
n = &((*n)->next);
--number_of_nodes_to_create;
}
}
void DestroyList(node *starting_node) {
while (starting_node) {
node *n = starting_node->next;
delete starting_node;
starting_node = n;
}
}
int main() {
node* head = NULL;
CreateList(head, 5);
...
DestroyList(head);
}
Online Demo
Though, it is not usual for a list creation to take an existing node as input. Usually the creation should create the list and then return the 1st (head) node, eg:
#include <iostream>
#include <vector>
using namespace std;
class node{
public:
int value;
node *next;
node() : value(0), next(NULL) {}
};
node* CreateList(int number_of_nodes_to_create){
node *head = NULL, **n = &head;
while (number_of_nodes_to_create > 0) {
*n = new node;
n = &((*n)->next);
--number_of_nodes_to_create;
}
return head;
}
void DestroyList(node *head) {
while (head) {
node *n = head->next;
delete head;
head = n;
}
}
int main() {
node* head = CreateList(5);
...
DestroyList(head);
}
Online Demo

Multithreading in n-ary tree

I have tried to use multithreading in n-ary tree in the lock_it() function. Saw all the tutorials present. But i am unable to come up the code. I only able to remove the deadlocks but i want to maximize the parallel running of lock_it() function.
Read at this link to know what lock_it() does.
https://www.geeksforgeeks.org/locking-and-unlocking-of-resources-in-the-form-of-n-ary-tree/
How to improve it?
#include <bits/stdc++.h>
#include <thread>
#include <mutex>
using namespace std;
class Node {
public:
char key;
bool locked;
int cnt_locked_desc;
Node* parent;
vector<Node*> child;
};
Node* root = NULL;
mutex mtx;
class LockUnlock {
public:
Node* newNode(char node_key, Node* prt) {
Node* tmp = new Node;
(*tmp).key = node_key;
(*tmp).locked = (*tmp).cnt_locked_desc = 0;
(*tmp).parent = prt;
return tmp;
}
bool lock_it(Node* node) { //O(h)
if ((*node).cnt_locked_desc > 0 || node == NULL)
return 0;
for (Node* curr = node; curr != NULL; curr = (*curr).parent)
if ((*curr).locked)
return 0;
mtx.lock();
for (Node* curr = node; curr != NULL; curr = (*curr).parent) {
(*curr).cnt_locked_desc++;
}
mtx.unlock();
(*node).locked = 1;
return 1;
}
};
Please consider using a scoped_lock index of directly using the mutex.
std::lock_guard or std::scoped_lock?
Concurrency is a tough subject. If you're interested in learning more on it, I really enjoyed this book: https://www.manning.com/books/c-plus-plus-concurrency-in-action-second-edition
And this course: https://www.udemy.com/course/modern-cpp-concurrency-in-depth/
I also highly recommend this course: https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-172-performance-engineering-of-software-systems-fall-2018/

Linked list with nodes

I am trying to make a linked list and test it in c++ using nodes. I create six nodes and then I print them forward and backwards like this:
main.cpp
#include "LinkedList.h"
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
void TestAddHead();
int main()
{
TestAddHead();
system("pause");
return 0;
}
void TestAddHead()
{
cout << "Testing AddHead()" << endl;
LinkedList<int> data;
for (int i = 0; i < 12; i += 2)
data.AddHead(i);
cout << "Node count: " << data.NodeCount() << endl;
cout << "Print list forward:" << endl;
data.PrintForward();
cout << "Print list in reverse:" << endl;
data.PrintReverse();
}
LinkedList.h
#pragma once
#include <iostream>
#include <vector>
#include <array>
#include <stdexcept>
#include <string>
using namespace std;
template<typename T>
class LinkedList
{
public:
struct Node
{
T data_;
Node* next;
Node* previous;
};
void PrintForward() const;
void PrintReverse() const;
unsigned int NodeCount() const;
void AddHead(const T &data);
LinkedList();
LinkedList(const LinkedList<T> &list);
~LinkedList();
private:
Node* head = new Node;
Node* tail = new Node;
unsigned int count = 0;
};
template<typename T>
LinkedList<T>::LinkedList()
{
}
template<typename T>
LinkedList<T>::LinkedList(const LinkedList<T> &list)
{
}
template<typename T>
LinkedList<T>::~LinkedList()
{
}
template<typename T>
void LinkedList<T>::AddHead(const T &data)
{
Node* newNode = new Node;
newNode->data_ = data;
if (count == 0)
{
head = newNode;
tail = newNode;
head->next = nullptr;
head->previous = nullptr;
}
else
{
newNode->next = head;
head->previous = newNode;
head = newNode;
}
count = count + 1;
}
template<typename T>
void LinkedList<T>::PrintForward() const
{
Node* currentNode = head;
while (currentNode != nullptr)
{
cout << currentNode->data_ << endl;
currentNode = currentNode->next;
}
}
template<typename T>
void LinkedList<T>::PrintReverse() const
{
Node* currentNode2 = tail;
while (currentNode2 != nullptr)
{
cout << currentNode2->data_ << endl;
currentNode2 = currentNode2->previous;
}
}
template<typename T>
unsigned int LinkedList<T>::NodeCount() const
{
return count;
}
this should be the output of the program:
Testing AddHead()
Node count: 6
Print list forward:
10
8
6
4
2
0
Print list in reverse:
0
2
4
6
8
10
The program works and gives me the correct output but the problem is that it just crashes when it reaches the "10" at the bottom of the program and I don't know why, can anyone tell me why is this happening and a possible way to fix it? thank you
Your immediate problem, you never set the new node previous pointer to nullptr ( a problem that honestly should be rectified by a better constructed loop and/or a proper constructor for Node). Regardless, here...
template<typename T>
void LinkedList<T>::AddHead(const T &data)
{
Node* newNode = new Node;
newNode->data_ = data;
if (count == 0)
{
head = newNode;
tail = newNode;
head->next = nullptr;
head->previous = nullptr;
}
else
{
newNode->next = head;
newNode->previous = nullptr; // ADD THIS
head->previous = newNode;
head = newNode;
}
count = count + 1;
}
There are still several things wrong in this: memory leaks, empty copy-ctor and destructor, etc, but the above is the root of the current evil. That line could also be:
newNode->previous = head->previous;
but frankly that just confuses what you're doing. You're always landing your new nodes at the head of the list, so the previous member of said-same will always be nullptr (at least until you start studying circular lists).

Properly inserting a nodes into a Linked List C++

Good Evening! I am trying to create a C++ Linked List that will create a random number & store randoms in 100 nodes. I haven't gotten any errors in the code I created but when I run the program, the output loops the number "42" to the point where I have to terminate the program. Please help. The code is below.
#include <iostream>
#include <stdlib.h>
using namespace std;
struct Node{
int xdata;
Node* next;
};
struct Node *head;
void insert_node(int y)
{
Node* temp = new Node;
temp-> xdata = y;
temp-> next = NULL;
if(head==NULL)
{
head=temp;
}
else{
temp->next=head;
head=temp;
}
};
int main(){
int z =rand()%100 + 1;
for(int i=0; i<100; i++)
{
insert_node(z);
}
while(head!=NULL)
{
cout<<head->xdata<<" "<<endl;
}
return 0;
}
You need to advance your head pointer.
while(head!=NULL)
{
cout<<head->xdata<<" "<<endl;
head = head->next;
}

Adding random numbers into a linked-list using loop

I want to add a completely random number into a linked-list, but instead of having all of my code in main, I want to use the object-oriented approach. I have my standard Node class and it's header, and then in main I want a loop that runs through 20 times and then stops adding more. I was given my insert function and how it would be called in main, but I can't seem to get the random numbers to work. I understand that you can't assign an int to a class, but I don't really know how else to incorporate my random number into my function in order to insert it into my list.
Here is my code. Observe the error on line 20 of main. Any insight would be great. Thanks!
Main.cpp
#include <iostream>
#include <iomanip>
#include <time.h>
#include "Node.h"
using namespace std;
int main()
{
srand(time(NULL));
Node link_head;
Node instance;
for (int i = 0; i < 20; i++)
{
int random = rand() % 100;
instance.insert(&link_head, &random);
}
}
Node.h
#include <iostream>
#include <iomanip>
#ifndef NODE_H
#define NODE_H
typedef int ElementType;
class Node
{
public:
Node();
ElementType data;
Node *next;
int insert(Node *, Node *);
};
#endif NODE_H
Node.cpp
#include <iomanip>
#include <iostream>
#include "Node.h"
using namespace std;
Node::Node()
{
this -> data = 0;
this -> next = NULL;
}
int Node::insert(Node *link_head, Node *newNode)
{
Node *current = link_head;
while (true)
{
if(current->next == NULL)
{
current->next = newNode;
break;
}
current = current->next;
}
return 0;
}
You are sending the address of an int to a function requiring a pointer on a Node. Allocate a new node first then send it to the function.
for (int i = 0; i < 20; i++)
{
int random = rand() % 100;
Node* newNode = new Node;
newNode->data = random;
instance.insert(&linkHead, newNode);
}
As stated, insert method should really be static of even a free function since it access only public members of the struct.
Your code is flawed in several ways.
instance.insert(&link_head, &random); &random doesn't point to a Node, thus the compiler error
int insert(Node *, Node *); should be static int insert(Node **, Node *); and used as follows
Node* head = NULL;
for (int i = 0; i < 20; i++)
{
Node* newNode = new Node;
newNode->data = rand() % 100;
Node::insert(&head, newNode);
}
Where the implementation looks like:
int Node::insert(Node** link_head, Node *newNode)
{
if(!link_head) {
return -1;
}
if(!(*link_head)) {
*link_head = newNode;
}
else {
newNode->next = (*link_head)->next;
(*link_head)->next = new_node;
}
return 0;
}
The difference is you use a head reference as an anchor for the linked list and you'll not have a useless instance that always needs to be sorted out from the actual values stored in the list.