I am trying to compile some c code with multithreading and for some reason I'm getting a segmentation fault in the Ubuntu WSL terminal when I try to run:
gcc -o mashu concurrent_list.c concurrent_list.h
The files I am trying to run are the following:
concurrent_list.c:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "concurrent_list.h"
struct node {
int value;
node* next;
pthread_mutex_t* lock;
// add more fields
};
struct list {
// add fields
node* head;
pthread_mutex_t* lock;
};
void print_node(node* node)
{
// DO NOT DELETE
if(node)
{
printf("%d ", node->value);
}
}
list* create_list()
{
// add code here
list* l = malloc(sizeof(list));
if(l == NULL){
printf("malloc error");
}
l->head = NULL;
l->head->next = NULL;
if(pthread_mutex_init(l->lock, NULL) != 0){
printf("mutex init failed\n");
}
if(pthread_mutex_init(l->head->lock, NULL) != 0){
printf("mutex init failed\n");
}
return l;
}
void delete_list(list* list)
{
// add code here
pthread_mutex_lock(list->lock);
node* head = list->head;
node* next = head->next;
while(next->next != NULL){
free(head);
next = next->next;
head = next;
}
pthread_mutex_unlock(list->lock);
free(list);
}
void insert_value(list* list, int value)
{
// add code here
// if the list is empty
pthread_mutex_lock(list->lock);
if(list->head == NULL){
list->head->value = value;
pthread_mutex_unlock(list->lock);
}
else{
// init newnode
node* newNode = malloc(sizeof(node));
if(!newNode){
printf("malloc failed\n");
}
newNode->value = value;
newNode->next = NULL;
if(pthread_mutex_init(newNode->lock, NULL) != 0){
printf("mutex init failed\n");
}
node* curr = list->head;
// lock the list and the first node
pthread_mutex_lock(curr->lock);
if(curr->next == NULL){ // first and only node at the start of a list
if(curr->value > value){ // insert the newnode at the beggining
list->head = newNode;
newNode->next = curr;
}else{
curr->next = newNode;
}
pthread_mutex_unlock(list->lock);
pthread_mutex_unlock(curr->lock);
// finished the insert
}
else{
node* prev = curr;
curr = curr->next;
pthread_mutex_unlock(list->lock);
pthread_mutex_lock(curr->lock);
while(curr->value < value && curr->next != NULL){
pthread_mutex_unlock(prev->lock);
prev = curr;
curr = curr->next;
pthread_mutex_lock(curr->lock);
}
if(curr->next == NULL){
curr->next = newNode;
}else{
prev->next = newNode;
newNode->next = curr;
}
pthread_mutex_unlock(prev->lock);
pthread_mutex_unlock(curr->lock);
}
}
}
void remove_value(list* list, int value)
{
// add code here
}
void print_list(list* list)
{
// add code here
node* curr = list->head;
pthread_mutex_lock(list->lock);
if(curr != NULL){
pthread_mutex_unlock(list->lock);
while(curr != NULL){
pthread_mutex_lock(curr->lock);
print_node(curr);
curr = curr->next;
pthread_mutex_unlock(curr->lock);
}
}
printf("\n"); // DO NOT DELETE
}
void count_list(list* list, int (*predicate)(int))
{
int count = 0; // DO NOT DELETE
// add code here
printf("%d items were counted\n", count); // DO NOT DELETE
}
int main(){
list* l = create_list();
printf("1\n");
insert_value(l,6);
printf("2\n");
insert_value(l,12);
insert_value(l,3);
insert_value(l,19);
insert_value(l,8);
printf("3\n");
print_list(l);
printf("4\n");
delete_list(l);
}
concurrent_list.h:
typedef struct node node;
typedef struct list list;
list* create_list();
void delete_list(list* list);
void print_list(list* list);
void insert_value(list* list, int value);
void remove_value(list* list, int value);
void count_list(list* list, int (*predicate)(int));
The thrown error when compiling is:
Segmentation fault
Am I accessing illegal memory, not compiling correctly or am I using mutex threads wrong?
Any help would be appriciated.
CodePudding user response:
create_list()
:
l->head = NULL
will segfault ifmalloc
failed. You probably want toreturn NULL;
in addition to the print.l->head->next = NULL;
will always segfault as you setl->head
toNULL
pthread_mutex_init(l->head->lock, NULL)
will always segfault asl->head
isNULL
.
insert_value()
:
list->head->value = value;
will segfault iflist->head
isNULL
. You even ensure that it is with the if statement.
As you lock the list on modification (and you need to do that at least for the head changes) I eliminated the node lock. Inlined print_node()
in print_list()
as the former required caller to take a lock which is risky. Fixed create_list()
per above. Simplified delete_list()
. Fixed (per above) and simplified insert_value()
. Removed dead code remove_value()
:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct node node;
struct node {
int value;
node *next;
};
typedef struct list list;
struct list {
node *head;
pthread_mutex_t *lock;
};
list* create_list();
void delete_list(list* list);
list *insert_value(list* list, int value);
void print_list(list* list);
list* create_list() {
list* l = malloc(sizeof(*l));
if(!l) {
printf("malloc error");
return NULL;
}
l->head = NULL;
if(pthread_mutex_init(l->lock, NULL) != 0) {
printf("mutex init failed\n");
}
return l;
}
void delete_list(list *l) {
pthread_mutex_lock(l->lock);
while(l->head) {
node *n = l->head;
l->head = l->head->next;
free(n);
}
free(l);
pthread_mutex_unlock(l->lock);
}
list *insert_value(list *l, int value) {
node* newNode = malloc(sizeof(node));
if(!newNode){
printf("malloc failed\n");
return NULL;
}
newNode->value = value;
// head
pthread_mutex_lock(l->lock);
if(!l->head || value < l->head->value){
newNode->next = l->head;
l->head = newNode;
pthread_mutex_unlock(l->lock);
return l;
}
// non-head
node *n = l->head;
for(; n->next && value >= n->next->value; n = n->next);
newNode->next = n->next;
n->next = newNode;
pthread_mutex_unlock(l->lock);
return l;
}
void print_list(list *l) {
pthread_mutex_lock(l->lock);
for(node *n = l->head; n; n = n->next) {
printf("%d ", n->value);
}
pthread_mutex_unlock(l->lock);
printf("\n");
}
int main(){
list* l = create_list();
printf("1\n");
insert_value(l, 6);
printf("2\n");
insert_value(l,12);
insert_value(l,3);
insert_value(l,19);
insert_value(l,8);
printf("3\n");
print_list(l);
printf("4\n");
delete_list(l);
}
and the output is:
1
2
3
3 6 8 12 19
4