Why does this error occur when I run my code?
error: RUN FINISHED; Segmentation fault: 11; real time: 3s; user: 0ms; system: 0m
I'm creating 10 threads where each thread is a ticket seller. There is a 10by10 array that holds the seats of the tickets. Depending on the type of the ticket-seller a person will be sold that specific seat.
Is the issue with the pthreads?
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/*
* File: ticketsellers.c
* Author: iantheflyinghawaiian
*
* Created on July 4, 2016, 11:27 AM
*/
#include <stdio.h>
#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// seller thread to serve one time slice (1 minute)
int theatre[10][10] ;
struct node
{
int info;
struct node *ptr;
}*front,*rear,*temp,*front1;
int count = 0;
/* Create an empty queue */
void create()
{
front = rear = NULL;
}
/* Returns queue size */
void queuesize()
{
printf("\n Queue size : %d", count);
}
/* Enqueing the queue */
void enq(int data)
{
if (rear == NULL)
{
rear = (struct node *)malloc(1*sizeof(struct node));
rear->ptr = NULL;
rear->info = data;
front = rear;
}
else
{
temp=(struct node *)malloc(1*sizeof(struct node));
rear->ptr = temp;
temp->info = data;
temp->ptr = NULL;
rear = temp;
}
count++;
}
/* Displaying the queue elements */
void display()
{
front1 = front;
if ((front1 == NULL) && (rear == NULL))
{
printf("Queue is empty");
return;
}
while (front1 != rear)
{
printf("%d ", front1->info);
front1 = front1->ptr;
}
if (front1 == rear)
printf("%d", front1->info);
}
/* Dequeing the queue */
void deq()
{
front1 = front;
if (front1 == NULL)
{
printf("\n Error: Trying to display elements from empty queue");
return;
}
else
if (front1->ptr != NULL)
{
front1 = front1->ptr;
printf("\n Dequed value : %d", front->info);
free(front);
front = front1;
}
else
{
printf("\n Dequed value : %d", front->info);
free(front);
front = NULL;
rear = NULL;
}
count--;
}
/* Returns the front element of queue */
int frontelement()
{
if ((front != NULL) && (rear != NULL))
return(front->info);
else
return 0;
}
/* Display if queue is empty or not */
void empty()
{
if ((front == NULL) && (rear == NULL))
printf("\n Queue empty");
else
printf("Queue not empty");
}
//Ticket Seller
void * sell(char *seller_type)
{
char seller_type1;
seller_type1 = *seller_type;
int i;
i = 0;
while (i == 0);
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
// Serve any buyer available in this seller queue that is ready
// now to buy ticket till done with all relevant buyers in their queue
//………………
// Case statements for seller_types
switch(seller_type1)
{
case 'H' :
printf("Seller type: H\n");
i = 1;
break;
case 'M' :
printf("Seller type: M\n");
i = 1;
break;
case 'L' :
printf("Seller type: L\n");
i = 1;
break;
}
}
return NULL; // thread exits
}
void wakeup_all_seller_threads()
{
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}
int main()
{
int i, N;
pthread_t tids[10];
printf("Enter N value of Customers: ");
scanf("%d", &N);
printf("Number of Customers: %d", N);
char seller_type;
// Create necessary data structures for the simulator.
// Create buyers list for each seller ticket queue based on the
// N value within an hour and have them in the seller queue.
// Create 10 threads representing the 10 sellers.
seller_type = 'H';
pthread_create(&tids[i], NULL, sell, &seller_type);
seller_type = 'M';
for (i = 1; i < 4; i++)
pthread_create(&tids[i], NULL, sell, &seller_type);
seller_type = 'L';
for (i = 4; i < 10; i++)
pthread_create(&tids[i], NULL, sell, &seller_type);
// wakeup all seller threads
wakeup_all_seller_threads();
// wait for all seller threads to exit
for (i = 0 ; i < 10 ; i++)
pthread_join(&tids[i], NULL);
// Printout simulation results
//…………
exit(0);
}
As already assumed by #2501: the culprit causing the segfault was the uninitialized variable i in main.
I took the liberty to write a minimal example for your pthread-creating, with the addition of some printf`s.
It compiles without warnings with
gcc -W -Wall threadtest.c -o threadtest -pthread
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
struct seller_type {
char st;
int tid;
};
void *sell(void *arg)
{
struct seller_type *seller_type1 = arg;
int i;
i = 0;
printf("thread #%d: seller_type1->st = %c\n", seller_type1->tid,
seller_type1->st);
// no semicolon after while()
while (i == 0) {
switch (seller_type1->st) {
case 'H':
printf("Seller type: H\n");
i = 1;
break;
case 'M':
printf("Seller type: M\n");
i = 1;
break;
case 'L':
printf("Seller type: L\n");
i = 1;
break;
}
}
printf("thread #%d: Work done\n", seller_type1->tid);
return NULL;
}
int main()
{
int i = 0;
struct seller_type *seller_type1;
pthread_t tids[10];
seller_type1 = calloc(10, sizeof(struct seller_type));
// All error handling ommitted! Yes, ALL!
seller_type1[0].st = 'H';
seller_type1[0].tid = 0;
pthread_create(&tids[0], NULL, sell, &seller_type1[0]);
for (i = 1; i < 4; i++) {
seller_type1[i].st = 'M';
seller_type1[i].tid = i;
pthread_create(&tids[i], NULL, sell, &seller_type1[i]);
}
for (i = 4; i < 10; i++) {
seller_type1[i].st = 'L';
seller_type1[i].tid = i;
pthread_create(&tids[i], NULL, sell, &seller_type1[i]);
}
puts("All threads created");
// wait for all seller threads to exit
for (i = 0; i < 10; i++) {
pthread_join(tids[i], NULL);
printf("Thread %d joined\n", i);
}
puts("All threads joined");
exit(EXIT_SUCCESS);
}
I hope you can build upon that.
You have a data race when you pass seller_type to the newly created thread, while at the same time modify the variable in the main.
The type of the function passed to pthread_create must be: void*(*)(void*), not the type you're using.
Function pthread_join requires a type pthread_t as the first argument, not a pointer to that type, which is what you're passing to it.
The variable i in the main isn't initialized, and is used to index the array tids, in the first pthread_create call.
All of those four problems cause undefined behavior by themselves. I suspect the last one causes the crash.
Related
I'm making simple patient managing program using circular queue but q.rear always have "0" value while executing exit_hos()
I thought that addq() makes variable "rear" different, but It doesn't work.
is_empty() always return front and rear is same.
I think I'm misunderstanding some codes and memory concepts.
how can I fix these functions?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 50
#define MAX_QUEUE_SIZE 6
typedef struct {
char** value;
int front;
int rear;
} Queue;
void init_queue(Queue* q) {
q->value = (char**)malloc(sizeof(char*) * MAX_QUEUE_SIZE);
q->front = 0;
q->rear = 0;
}
int is_full(Queue* q) {
if (((q->rear +1) % MAX_QUEUE_SIZE) == q->front)
return 1;
else
return 0;
}
int is_empty(Queue* q) {
if (q->front == q->rear)
return 1;
else
return 0;
}
void addq(Queue* q, char* value) {
q->rear = (q->rear+1) % MAX_QUEUE_SIZE;
q->value[q->rear] = value;
printf("addq: %s", value);
return;
}
char* deleteq(Queue* q) {
q->front = (q->front + 1) % MAX_QUEUE_SIZE;
return q->value[q->front];
}
void arrive(Queue q) {
int input;
char name[MAX_SIZE];
printf("\n");
printf("1. submit\n");
printf("2. cancel\n");
scanf("%d", &input);
if (input == 1) {
if (is_full(&q) == 1) {
printf("Service is not available\n");
}
else {
printf("name: ");
scanf("%s", name);
addq(&q, name);
}
}
else if (input == 2) {
return;
}
else {
printf("input error\n");
return;
}
return;
}
void exit_hos(Queue q) {
char patient[MAX_SIZE];
if (is_empty(&q) == 1)
{
printf("There is no patient waiting\n");
}
else {
strcpy(patient, deleteq(&q));
printf("patient: %s", patient);
}
return;
}
int main() {
int input;
Queue q;
init_queue(&q);
while (1)
{
printf("\nINPUT\n");
printf("1. Arrive hostpital\n");
printf("2. Exit hospital\n");
printf("3. service exit\n");
scanf("%d", &input);
if (input == 1)
arrive(q);
else if (input == 2) {
exit_hos(q);
}
else if (input == 3) {
printf("exit\n");
return 0;
}
else {
printf("input error\n");
}
}
free(q.value);
return 0;
}
I think that this line is wrong:
q->value = (char**)malloc(sizeof(char*) * MAX_QUEUE_SIZE);
I think that it should be:
char * _value = (char*)malloc(sizeof(char*) * MAX_QUEUE_SIZE);
q->value = &_value;
malloc is going to return a pointer to a char array. q->value is a pointer to a pointer to a char array. So you want to set it to the address of the char array that malloc is created for you.
Change you init_queue code to this and it will work:
void init_queue(Queue* q) {
char * _value = (char*)malloc(sizeof(char*) * MAX_QUEUE_SIZE);
q->value = &_value;
q->front = 0;
q->rear = 0;
}
Output:
Chris#DESKTOP-BCMC1RF ~
$ ./main.exe
INPUT
1. Arrive hostpital
2. Exit hospital
3. service exit
1
1. submit
2. cancel
1
name: fred
addq: fred
INPUT
1. Arrive hostpital
2. Exit hospital
3. service exit
2
If you already have a max queue size and a max size, you are better off pre-allocating the whole thing as an array, reducing memory headaches. As a general rule, avoid headaches unless they provide a feature you want.
Note: This method of keeping track of and re-using memory is called a circular buffer (not to be confused with the linked list types that are more commonly called queues).
#define MAX_SIZE 50
#define MAX_QUEUE_SIZE 6
typedef struct {
char value [MAX_QUEUE_SIZE][MAX_SIZE + 1]; //+1 to hold extra null termination
unsigned int front;
unsigned int size; //size is a clearer than rear, which could have meant end item or end+1 and needed special empty queue handling
} Queue;
void init_queue(Queue* q) {
memset(q,0,sizeof(Queue)); //just zero it all
//more info on this and some situation-dependent alternatives https://stackoverflow.com/questions/11152160/initializing-a-struct-to-0
}
int is_full(const Queue* q) {
return q->size >= MAX_QUEUE_SIZE;
}
int is_empty(const Queue* q) {
return q->size == 0;
}
//sometimes called a push operation
//return 0 if failed
int addq(Queue* q, const char* value) {
//error check, abort, error handling section:
//full queue -> abort
if(is_full(q)) return 0;
//long value -> truncate handled via strncpy
//actual operation
const unsigned int destination = (q->front + q->size) % MAX_QUEUE_SIZE;
strncpy(q->value[destination],value,MAX_SIZE);
q->size = q->size + 1;
printf("addq: %s", q->value[destination]);
return q->size;
}
//sometimes called a pop operation
//return value may not persist if addq is called, but fine for your use of copying on call
const char* deleteq(Queue* q) {
if(is_empty(q)) return 0;
const char * retval = q->value[q->front];
q->front = (q->front + 1) % MAX_QUEUE_SIZE;
q->size = q->size - 1;
return retval;
}
also remember to use either MAX_SIZE + 1 or strncpy with MAX_SIZE - 1 since "No null-character is implicitly appended at the end of destination if source is longer than num."
(and strcpy and scanf as you sling them onto arrays is unsafe)
I'm trying to implement the producer consumer with conditional variables so I can learn about synchronization. I'm using the github to guide me and solved some seg faults but now it seems that my consumer never gets executed or is stuck in deadlock. I'm not sure what could be the error. I have included printf statements in the producer to execute everytime it runs and it completes producing any string in messages.txt less than 5. The consumer though does not and is stuck in a deadlock.
#define max 5
int par = 0;
// Data structure for queue
struct queue
{
char *items; // array to store queue elements
int maxsize; // maximum capacity of the queue
int front; // front points to front element in the queue (if any)
int rear; // rear points to last element in the queue
int size; // current capacity of the queue
pthread_mutex_t mutex; // needed to add/remove data from the buffer
pthread_cond_t can_produce; // signaled when items are removed
pthread_cond_t can_consume; // signaled when items are added
};
// Utility function to initialize queue
struct queue* newQueue(int size)
{
struct queue *pt = NULL;
pt = (struct queue*)malloc(sizeof(struct queue));
pt->items = (char*)malloc(size * sizeof(char));
pt->maxsize = size;
pt->front = 0;
pt->rear = -1;
pt->size = 0;
pthread_mutex_init(&pt->mutex, NULL);
pthread_cond_init(&pt->can_produce, NULL);
pthread_cond_init(&pt->can_consume, NULL);
return pt;
}
// Utility function to return the size of the queue
int size(struct queue *pt)
{
return pt->size;
}
// Utility function to check if the queue is empty or not
int isEmpty(struct queue *pt)
{
return !size(pt);
}
// Utility function to return front element in queue
char front(struct queue *pt)
{
if (isEmpty(pt))
{
//printf("UnderFlow\nProgram Terminated\n");
}
return pt->items[pt->front];
}
// Utility function to add an element x in the queue
void enqueue(struct queue *pt, char x)
{
if (size(pt) == pt->maxsize)
{
//printf("OverFlow\nProgram Terminated\n");
}
//printf("Inserting %c\t", x);
pt->rear = (pt->rear + 1) % pt->maxsize; // circular queue
pt->items[pt->rear] = x;
pt->size++;
//printf("front = %c, rear = %c\n", pt->front, pt->rear);
}
// Utility function to remove element from the queue
void dequeue(struct queue *pt)
{
if (isEmpty(pt)) // front == rear
{
//printf("UnderFlow\nProgram Terminated\n");
}
//printf("Removing %c\t", front(pt));
pt->front = (pt->front + 1) % pt->maxsize; // circular queue
pt->size--;
//printf("front = %d, rear = %c\n", pt->front, pt->rear);
}
void consumer_f(void *arg)
{
struct queue *pt = (struct queue*)arg;
while (par==0 && !isEmpty(pt))
{
pthread_mutex_lock(&pt->mutex);
if (pt->size == 0)
{ // empty
// wait for new items to be appended to the buffer
pthread_cond_wait(&pt->can_consume, &pt->mutex);
}
printf("%c", pt->front);
dequeue(pt);
pthread_cond_signal(&pt->can_produce);
pthread_mutex_unlock(&pt->mutex);
}
}
void producer_f(void *arg)
{
struct queue *pt = (struct queue*)arg;
char tmp;
FILE *fp;
fp = fopen("messages.txt", "r");
if (fp == NULL)
{
//fprintf(stderr, "error opening messages.txt");
return -1;
}
while ((tmp = fgetc(fp)) != EOF)
{
pthread_mutex_lock(&pt->mutex);
if (pt->size == max)
pthread_cond_wait(&pt->can_produce, &pt->mutex);
enqueue(pt, tmp);
printf("sent");
pthread_cond_signal(&pt->can_consume);
pthread_mutex_unlock(&pt->mutex);
}
par = 1; //denotes EOF for consumer */
}
int main()
{
printf("nop");
struct queue *pt = newQueue(5);
pthread_t producer;
pthread_t consumer;
printf("got here");
if (pthread_create(&producer, NULL, &producer_f, pt))
{
//fprintf(stderr, "Error creating producer thread\n");
return -1;
}
if (pthread_create(&consumer, NULL, &consumer_f, pt))
{
//fprintf(stderr, "Error creating consumer thread\n");
return -1;
}
if (pthread_join(producer_f, NULL))
{
//fprintf(stderr, "Error joining proucer thread\n");
return -1;
}
if (pthread_join(consumer_f, NULL))
{
//fprintf(stderr, "Error joinging consumer thread\n");
return -1;
}
return 0;
}
The consumer thread is not going to deadlock state but it is exiting without consuming as EOS is reached before consumer started consuming.
As you know, threads can get scheduled in a random way by OS (I mean, at least you can assume that they get scheduled in a random way). With this assumption, the producer might have started and read all bytes and enabled eos flag i.e. par=1. If consumer thread starts after par=1, it is not consuming at all.
To handle this case, you need to update the consumer_f() function.
while (1) //Run the loop always
{
pthread_mutex_lock(&pt->mutex);
if ((pt->size == 0) && (par == 0)) //Make sure that EOS is not already reached.
{ // empty
// wait for new items to be appended to the buffer
pthread_cond_wait(&pt->can_consume, &pt->mutex);
}
if(par && isEmpty(pt))
{
//If Array is empty and eos is reached, unlock and exit loop
pthread_mutex_lock(&pt->mutex);
break;
}
//Other code
}
Similarly, you need to enable eos flag inside mutex in producer_f().
while ((tmp = fgetc(fp)) != EOF)
{
//Your code
}
pthread_mutex_lock(&pt->mutex);
par = 1;
pthread_cond_signal(&pt->can_consume); //To make sure that consumer thread wakesup
pthread_mutex_unlock(&pt->mutex);
PS: pt->size == 0 can be replaced with isEmpty(pt) for more readability.
I am trying to write a code that is using threads in order to find files that contain a specific string in their name.
My code works most of the times. in some specific cases, threads are not able to acquire locks for some reason.
I tried debugging really hard (using prints, as you can see in the code) but I couldn't find the problem.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
void* threadFunction(void* searchTerm);
bool scanDirName(char * path, char * searchTerm);
int numOfThreads;
pthread_mutex_t qlock;
pthread_cond_t cond;
int count;
int matchingFiles;
struct Node {
char* data;
struct Node* next;
};
// Two global variables to store an address of front and rear nodes.
struct Node* front = NULL;
struct Node* rear = NULL;
// To Enqueue an integer
void Enqueue(char* x) {
/* printf("\nhere\n");*/
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
temp->data =x;
temp->next = NULL;
if(front == NULL && rear == NULL){
front = rear = temp;
pthread_cond_signal(&cond);
return;
}
rear->next = temp;
rear = temp;
}
// To Dequeue an integer.
char* Dequeue() {
struct Node* temp = front;
if(front == NULL) {
return NULL;
}
char* data;
data = front->data;
if(front == rear) {
front = rear = NULL;
}
else {
front = front->next;
}
// printf("\nfreeing %p, %s\n", temp, temp->data);
free(temp);
return data;
}
void* threadFunction(void* st) {
bool isFinished;
isFinished = false;
pthread_mutex_lock(&qlock);
while (true) {
char *filepath;
char *searchTerm;
searchTerm = (char *) st;
filepath = Dequeue();
pthread_mutex_unlock(&qlock);
if (filepath == NULL) {
printf("%ld waiting for lock \n",(long) pthread_self());
pthread_mutex_lock(&qlock);
count++;
if (isFinished) {
printf("%ld waking u up, we found %d items!\n",(long) pthread_self(), matchingFiles);
pthread_cond_broadcast(&cond);
if (count == numOfThreads) {
printf("Thread exited: %ld\n", (long) pthread_self());
pthread_mutex_unlock(&qlock);
pthread_exit((void*)0);
}
}
isFinished = false;
printf("%ld going to sleep\n",(long) pthread_self());
pthread_cond_wait(&cond, &qlock);
printf("%ld Woke up, try to compare %d == %d\n",(long) pthread_self(), count, numOfThreads);
if (count == numOfThreads) {
printf("Thread exited: %ld\n", (long) pthread_self());
pthread_mutex_unlock(&qlock);
pthread_exit((void*)1);
}
printf("%ld compare failed \n",(long) pthread_self());
count--;
}
else {
printf("%ld deq 1 item \n",(long) pthread_self());
isFinished = scanDirName(filepath, searchTerm);
}
}
}
bool scanDirName(char * path, char * searchTerm){
DIR * d = opendir(path); // open the path
char* str3;
if(d==NULL) return false; // if was not able return
;
struct dirent * dir; // for the directory entries
while ((dir = readdir(d)) != NULL) // if we were able to read somehting from the directory
{
printf("%ld STARTED A ROUND!\n",(long) pthread_self());
if(dir-> d_type == DT_DIR){ //
if (dir->d_type == DT_DIR && strcmp(dir->d_name, ".") != 0 & strcmp(dir->d_name, "..") != 0) // if it is a directory
{
str3 = malloc((1+strlen("/")+ strlen(path)+ strlen(dir->d_name))*sizeof(char));
if (!str3){
return false;
}
strcpy(str3, path);
strcat(str3, "/");
strcat(str3, dir->d_name);
// printf("\n---\n%s\n---\n",str3);
printf("%ld waiting for lock in func \n",(long) pthread_self());
pthread_mutex_lock(&qlock);
printf("%ld wake threads \n",(long) pthread_self());
Enqueue(str3);
pthread_cond_signal(&cond);
printf("%ld enq \n",(long) pthread_self());
pthread_mutex_unlock(&qlock);
printf("%ld locks gone \n",(long) pthread_self());
}
}
else if(dir-> d_type == DT_REG){ //
if(strstr(dir->d_name, searchTerm)){
matchingFiles++;
/*printf("%s/%s\n", path, dir->d_name);*/
}
}
printf("%ld finished A ROUND!\n",(long) pthread_self());
}
printf("%ld finished scanning!\n",(long) pthread_self());
fflush(stdout);
closedir(d); // finally close the directory
if (count == numOfThreads-1) {
return true;
}
return false;
}
int main(int argc, char* argv[]){
count = 0;
pthread_mutex_init(&qlock, NULL);
pthread_cond_init(&cond, NULL);
matchingFiles = 0;
if (argc != 4){
printf("ERROR\n");
exit(1);
}
char* rootSearchDir = argv[1];
char* searchTerm = argv[2];
int threadsNumber = atoi(argv[3]);
pthread_t threadsCollection[threadsNumber];
Enqueue(rootSearchDir);
numOfThreads = threadsNumber;
int i;
for (i=0; i<threadsNumber; i++){
if(pthread_create(&threadsCollection[i], NULL, threadFunction, (void*)searchTerm)) {
fprintf(stderr, "Error creating thread\n");
pthread_mutex_destroy(&qlock);
return 1;
}
}
int rc;
for (i=0; i<threadsNumber; i++){
rc = pthread_join((threadsCollection[i]), NULL);
if(rc) {
fprintf(stderr, "Error joining thread, %d\n", rc);
pthread_mutex_destroy(&qlock);
return 1;
}
}
}
I have attached all of the code (maybe it is important) but I suspect the problem is in scanDirName or threadFunction.
--- EDIT ---
I found the problem. I had a logical problem with the locks, fixed it.
Thanks all!
if filepath = Dequeue() returns a non-null; then your next iteration of this loop will call Dequeue() without holding &qlock. If you checked the return values, you would notice this.
scanDirName relies on count to set its return value; however it isn’t protected by qlock { see #1 }
If I read your code correctly, you are attempting to make a sort of dispatch mechanism, where names are emitted from scanDir() into a queue, and pulled from the queue, where a fresh scanDir() is spun up for each item. The handling of count is an attempt to detect whether the Dequeue failed because there is nothing left to do, or everyone is busy doing scanDirs.
There is a bit easier of a mechanism: use two queues. Scandir dumps entries into say “NameQ”, and thread function pulls names out of NameQ, dumping them into WorkQ. When a thread runs out of NameQ items, it looks into WorkQ for fresh ones to dispatch. Then you just have to keep track of how many threads are in scanDir(). If both queues are empty, and number of threads in scanDir is zero, there is nothing more to do. Your Basic logic ends up looking like this:
void* threadFunction(void* st) {
static int nreader = 0;
int ncount = 0, wcount = 0;
char *searchTerm;
searchTerm = (char *) st;
Menter(&qlock);
while (nreader || !(empty(&Names) && empty(&Work))) {
char *filepath;
filepath = Dequeue(&Names);
if (filepath) {
ncount++;
Enqueue(&Work, filepath);
} else if ((filepath = Dequeue(&Work)) != NULL) {
wcount++;
nreader++;
Mexit(&qlock);
scanDirName(filepath, searchTerm);
Menter(&qlock);
nreader--;
cv_wake(&cond);
} else {
cv_wait(&cond, &qlock);
}
}
Mexit(&qlock);
printf("%p: %d, %d items\n", pthread_self(), ncount, wcount);
return NULL;
}
Mexit, Menter are error checking covers for the posix funs, and a lot easier on the eyes than all that redundant typing...
static int menter(pthread_mutex_t *m, int line) {
if (pthread_mutex_lock(m) != 0) {
fprintf(stderr, "%p:%d Mutex lock failed!\n", pthread_self(),line);
abort();
}
DEBUG_LOCK("%d locked\n", line);
return 0;
}
#define Menter(x) menter((x), __LINE__)
static int mexit(pthread_mutex_t *m, int line) {
DEBUG_LOCK("%d unlocked\n", line);
if (pthread_mutex_unlock(m) != 0) {
fprintf(stderr, "%p:%d Mutex unlock failed!\n", pthread_self(),line);
abort();
}
return 0;
}
#define Mexit(x) mexit((x), __LINE__)
I am getting a seg fault error at my pthread_join line. Below is my thread creation and joining code as well as my my_func thread function that I am calling. The program is supposed to create a variable amount of threads to execute a grep like function.
int
parallelSearchStatic(char **argv)
{
pthread_t worker_thread[NUM_THREADS];
ARGS_FOR_THREAD *args_for_thread;
queue_element_t *element;
int i;
int num_occurrences = 0;
int queue_count = 0;
queue_t *queue = createQueue(); /* Create and initialize the queue data structure. */
DIR *d;
struct dirent *dir;
d = opendir(argv[2]);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
element = (queue_element_t *)malloc(sizeof(queue_element_t));
if(element == NULL){
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(element->path_name, argv[2]);
strcat(element->path_name, "/");
strcat(element->path_name, dir->d_name);
insertElement(queue, element);
queue_count++;
}
closedir(d);
}
int increment = queue_count/NUM_THREADS;
for(i=0;i<NUM_THREADS;i++){
args_for_thread = (ARGS_FOR_THREAD *)malloc(sizeof(ARGS_FOR_THREAD));
args_for_thread->threadID=i;
args_for_thread->queue=createQueue();
args_for_thread->args=argv;
for(i = 0; i < increment; i++)
{
insertElement(args_for_thread->queue, removeElement(queue));
queue_count--;
}
if(i == (NUM_THREADS - 1) && queue_count != 0)
{
for(i = 0; i < queue_count; i++)
{
insertElement(args_for_thread->queue, removeElement(queue));
}
}
if((pthread_create(&worker_thread[i], NULL, my_func, (void *)args_for_thread))!=0){
printf("Cannot create thread \n");
exit(0);
}
}
for(i=0;i<NUM_THREADS;i++)
{
pthread_join(worker_thread[i], NULL);
}
for(i = 0; i < NUM_THREADS; i++)
num_occurrences += countArray[i];
return num_occurrences;
}
void *my_func(void *this_arg)
{
ARGS_FOR_THREAD *args_for_me = (ARGS_FOR_THREAD *)this_arg; // Typecast the argument passed to this function to the appropriate type
int threadID = args_for_me->threadID;
queue_t *queue = args_for_me->queue;
char** args = args_for_me->args;
int count = 0;
while(queue->head != NULL)
{
queue_element_t *element = removeElement(queue);
char *a[5];
a[0] = args[0];
a[1] = args[1];
a[2] = element->path_name;
a[3] = args[3];
a[4] = args[4];
count += serialSearch(a);
}
countArray[threadID] = count;
free((void *)args_for_me); // Free up the structure
pthread_exit(NULL);
}
You are using re-using i in nested loops within an outer loop that also uses i as its counter variable:
for(i = 0; i < increment; i++)
and
for(i = 0; i < queue_count; i++)
This means that your pthread_create() (which follows these inner loops) is using the wrong value of i to access worker_thread[i], so some values of worker_thread[] remain uninitialised and then cause pthread_join() to crash.
Use a different variable (eg. j) for the inner loops.
I am writing my own user level thread library and am running into some issues. Below is the code of the library I have written thus far after the edits provided by you guys and also some introspection from my end:
struct tcb {
int thread_id;
int thread_pri;
ucontext_t thread_context;
struct tcb *next;
} *ready_head;
typedef struct tcb tcb;
tcb *running_head;
tcb *tmp,*tmp1,*tmp2,*temp;
// ucontext_t *ready;
// head = NULL;
// running_head = head;
void t_shutdown()
{
free(temp);
free(tmp);
free(tmp1);
free(ready_head);
free(running_head);
}
void t_yield()
{
// tmp2 = ready_head;
tmp1 = running_head;
/* tmp = running_head;
running_head = ready_head;
while(tmp1->next != NULL)
tmp1 = tmp1->next;
tmp1->next = tmp;
*/
insert(tmp1);
running_head = ready_head;
ready_head = ready_head->next;
printf("yield1\n");
swapcontext(&running_head->thread_context, &tmp1->thread_context);
printf("yield2\n");
// setcontext(&ready_head->thread_context);
}
void insert(tcb *a)
{
tcb *b;
if (ready_head == NULL)
{
ready_head = a;
}
else
{
b = ready_head;
while(b->next)
b = b->next;
b->next = a;
}
printf("insert\n");
}
void t_init()
{
tmp = (tcb *)malloc(sizeof(tcb));
getcontext(&tmp->thread_context); /* let tmp be the context of main() */
tmp->next = NULL;
running_head = tmp;
ready_head = NULL;
}
int t_create(void (*fct)(int), int id, int pri)
{
size_t sz = 0x10000;
temp = (tcb *)malloc(sizeof(tcb));
getcontext(&temp->thread_context);
temp->thread_id = id;
temp->thread_pri = pri;
temp->thread_context.uc_stack.ss_sp = malloc(sz); /* new statement */
temp->thread_context.uc_stack.ss_size = sz;
temp->thread_context.uc_stack.ss_flags = 0;
temp->thread_context.uc_link = &tmp->thread_context;
makecontext(&temp->thread_context, fct, 1, id);
insert(temp);
printf("1\n");
}
I am testing this library on the following test program:
void assign(void)
{
int i;
for (i = 0; i < 3; i++)
printf("in assign(1): %d\n", i);
t_yield();
for (i = 10; i < 13; i++)
printf("in assign(2): %d\n", i);
t_yield();
for (i = 20; i < 23; i++)
printf("in assign(3): %d\n", i);
}
int main(int argc, char **argv)
{
t_init();
t_create(assign, 1, 1);
printf("in main(): 0\n");
t_yield();
printf("in main(): 1\n");
t_yield();
printf("in main(): 2\n");
t_yield();
printf("done...\n");
return (0);
}
The expected output is:
in main(): 0
in assign(1): 0
in assign(1): 1
in assign(1): 2
in main(): 1
in assign(2): 10
in assign(2): 11
in assign(2): 12
in main(): 2
in assign(3): 20
in assign(3): 21
in assign(3): 22
done...
However, I am getting:
in main(): 0
in main(): 1
in main(): 2
done...
I now know that there is an issue with the swapcontext() as that does not seem to be working at all. I have tried to use printf statements to debug my program but am still unable to get this to work! Please help ....
It appears to me that in your t_yield() function you are actually swapping the ready_head context with the ready_head context. You might want to try
swapcontext(&tmp->thread_context, &running_head->thread_context);
instead.