Thread don't terminate their job - c

I am writing a concurrent C program where I want to wait for all threads to finish in the main().
Based on this solution, I wrote the following code in main():
// Create threads
pthread_t cid[num_mappers];
int t_iter;
for (t_iter = 0; t_iter < num_mappers; t_iter++){
pthread_create(&(cid[t_iter]), NULL, &map_consumer, NULL);
}
// Wait for all threads to finish
for (t_iter = 0; t_iter < num_mappers; t_iter++){
printf("Joining %d\n", t_iter);
int result = pthread_join(cid[t_iter], NULL);
}
printf("Done mapping.\n");
The function passed into threads is defined as:
// Consumer function for mapping phase
void *map_consumer(void *arg){
while (1){
pthread_mutex_lock(&g_lock);
if (g_cur >= g_numfull){
// No works to do, just quit
return NULL;
}
// Get the file name
char *filename = g_job_queue[g_cur];
g_cur++;
pthread_mutex_unlock(&g_lock);
// Do the mapping
printf("%s\n", filename);
g_map(filename);
}
}
The threads are all successfully created and executed, but the join loop will never finish if num_mappers >= 2.

You return without unlocking the mutex:
pthread_mutex_lock(&g_lock);
if (g_cur >= g_numfull){
// No works to do, just quit
return NULL; <-- mutex is still locked here
}
// Get the file name
char *filename = g_job_queue[g_cur];
g_cur++;
pthread_mutex_unlock(&g_lock);
So only one thread ever returns and ends - the first one, but since it never unlocks the mutex, the other threads remain blocked.
You need something more like
pthread_mutex_lock(&g_lock);
if (g_cur >= g_numfull){
// No works to do, just quit
pthread_mutex_unlock(&g_lock);
return NULL;
}
// Get the file name
char *filename = g_job_queue[g_cur];
g_cur++;
pthread_mutex_unlock(&g_lock);

Related

How do I write a string to a 2D array in C?

So I am working on a multi-threading program with 4 threads. For thread1 I am grabbing input from stdin and then putting it into buffer1, thread2 then reads from buffer1, modifies it, then puts it in buffer2 for thread3 to read, and so on....
After I have read from buffer1 (in my thread2 function), I have successfully altered the data, now I want to put it in buffer2, but I am getting the error of "expression must be a modifiable lvalue". Does anyone know why??
My thread 2 function is below and the error is appearing in buffer2[write2] = updatedStr;
void *line_separator_thread(void *args)
{
// Consuming from buffer 1 and producing to buffer 2
int haveStop = 0;
while (1)
{
// Snag the mutext for a read
pthread_mutex_lock(&mutex1);
// Release the mutex and block on the condition
pthread_cond_wait(&readyBuffer1, &mutex1);
// Process all unread slots from the buffer1 queue
while (buffer1[read1][0] != -1) // Look for no sentinal value
{
haveStop = haveStopInText(buffer1[read1]);
if (haveStop)
break;
// ***If no break, then read from buffer1, and modify \n to be a space?
// str_replace(orig, replace, with)
char *updatedStr = str_replace(buffer1[read1], "\n", " ");
printf("UPDATED STRING: %s\n", updatedStr);
read1 = (read1 + 1) % 5;
// ***Put the updated string in buffer 2?
pthread_mutex_lock(&mutex2);
buffer2[write2] = updatedStr; //ERROR IS HERE!!!
// ***Need to change buffer1[read1][0] So that it doesn't keep looping?
}
// ***Unlock the mutex here? Or outside of the while loop?
pthread_mutex_unlock(&mutex1);
}
return NULL;
Buffer variables and read/write variables are below
char buffer1[5][1000]; //inputThread + lineSeparatorThread
char buffer2[5][1000];
char buffer3[5][1000];
// Set up variables to let the threads know where is it safe to read from and write to
int write1 = 0;
int read1 = 0;
int write2 = 0;
int read2 = 0;
int write3 = 0;
int read3 = 0;
And lastly, below is in my main function where I am creating the 4 threads
pthread_create(&outputThread, &attr, output_thread, NULL);
usleep(100); // Force the program to allow output thread to actually come up and pend on readyBuffer 3 first
pthread_create(&plusSignThread, &attr, plus_sign_thread, NULL);
usleep(100); // Force the program to allow plus_sign_thread thread to actually come up first
pthread_create(&lineSeparatorThread, &attr, line_separator_thread, NULL);
usleep(100); // Force the program to allow line_separator_thread thread to actually come up first
pthread_create(&inputThread, &attr, input_thread, NULL);
pthread_join(inputThread, NULL);
pthread_join(lineSeparatorThread, NULL);
pthread_join(plusSignThread, NULL);
pthread_join(outputThread, NULL);

accept call blocking thread termination

I'm having trouble terminating my server in my multithreaded program (one server, multiple clients).
When the variable global_var, which counts the number of currently connected clients, gets set to 0, the server should terminate, but it doesn't.
What I think is happening is since accept() is blocking , the code never reaches the break condition in main loop.
It's breaking correctly out of thread_func but then it blocks inside the while loop, just before the accept() call and after printing "Exiting thread_func".
volatile int finished = 0; // Gets set to 1 by catching SIGINT/SIGSTOP
int global_var = 0; // When it gets to 0, server should terminate
int server_fd;
void * thread_func(void* arg)
{
do_some_pre_stuff();
while(1)
{
if(!global_var)
{
close(server_fd);
finished = 1;
break;
}
if(recv(...) > 0)
{
do_more_stuff()
}
else
{
disconnect_client();
global_var--;
break;
}
}
free_more_ressources();
return NULL;
}
int main()
{
do_initial_stuff();
init_socket();
listen();
while (!finished)
{
if( (fd = accept(server_fd,...)) == -1)
exit(-1);
global_var++;
/* Some intermediate code */
if(!global_var)
break;
// Thread for the newly connected player
if(pthread_create(&thread_id[...], NULL, thread_func, (void*)some_arg)
exit(-1);
}
free_resources();
puts("Exiting thread_func");
}
I tried the advice listed here without success (except the pipe answer, not trying to mess with pipes).
I'm new to socket programming but what I tried so far looked correct but none of the solutions worked (including semaphores, pthread_cancel,etc)
PS: synchronization has been implemented, just omitted here for readability

Simple C pthread test program hangs during execution

I'm new to using the pthread library in C and I have an assignment for my class to write a simple program using them. The basic description of the program is it takes 1 or more input files containing website names and 1 output file name. I then need to create 1 thread per input file to read in the website names and push them onto a queue. Then I need to create a couple of threads to pull those names off of the queue, find their IP Address, and then write that information out to the output file. The command line arguments are expected as follows:
./multi-lookup [one or more input files] [single output file name]
My issue is this. Whenever I run the program with only 1 thread to push information to the output file then everything works properly. When I make it two threads then the program hangs and none of my testing "printf" statements are even printed. My best guess is that deadlock is occurring somehow and that I'm not using my mutexes properly but I can't figure out how to fix it. Please help!
If you need any information that I'm not providing then just let me know. Sorry for the lack of comments in the code.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include "util.h"
#include "queue.h"
#define STRING_SIZE 1025
#define INPUTFS "%1024s"
#define USAGE "<inputFilePath> <outputFilePath>"
#define NUM_RESOLVERS 2
queue q;
pthread_mutex_t locks[2];
int requestors_finished;
void* requestors(void* input_file);
void* resolvers(void* output_file);
int main(int argc, char* argv[])
{
FILE* inputfp = NULL;
FILE* outputfp = NULL;
char errorstr[STRING_SIZE];
pthread_t requestor_threads[argc - 2];
pthread_t resolver_threads[NUM_RESOLVERS];
int return_code;
requestors_finished = 0;
if(queue_init(&q, 10) == QUEUE_FAILURE)
fprintf(stderr, "Error: queue_init failed!\n");
if(argc < 3)
{
fprintf(stderr, "Not enough arguments: %d\n", (argc - 1));
fprintf(stderr, "Usage:\n %s %s\n", argv[0], USAGE);
return 1;
}
pthread_mutex_init(&locks[0], NULL);
pthread_mutex_init(&locks[1], NULL);
int i;
for(i = 0; i < (argc - 2); i++)
{
inputfp = fopen(argv[i+1], "r");
if(!inputfp)
{
sprintf(errorstr, "Error Opening Input File: %s", argv[i]);
perror(errorstr);
break;
}
return_code = pthread_create(&(requestor_threads[i]), NULL, requestors, inputfp);
if(return_code)
{
printf("ERROR: return code from pthread_create() is %d\n", return_code);
exit(1);
}
}
outputfp = fopen(argv[i+1], "w");
if(!outputfp)
{
sprintf(errorstr, "Errord opening Output File: %s", argv[i+1]);
perror(errorstr);
exit(1);
}
for(i = 0; i < NUM_RESOLVERS; i++)
{
return_code = pthread_create(&(resolver_threads[i]), NULL, resolvers, outputfp);
if(return_code)
{
printf("ERROR: return code from pthread_create() is %d\n", return_code);
exit(1);
}
}
for(i = 0; i < (argc - 2); i++)
pthread_join(requestor_threads[i], NULL);
requestors_finished = 1;
for(i = 0; i < NUM_RESOLVERS; i++)
pthread_join(resolver_threads[i], NULL);
pthread_mutex_destroy(&locks[0]);
pthread_mutex_destroy(&locks[1]);
return 0;
}
void* requestors(void* input_file)
{
char* hostname = (char*) malloc(STRING_SIZE);
FILE* input = input_file;
while(fscanf(input, INPUTFS, hostname) > 0)
{
while(queue_is_full(&q))
usleep((rand()%100));
if(!queue_is_full(&q))
{
pthread_mutex_lock(&locks[0]);
if(queue_push(&q, (void*)hostname) == QUEUE_FAILURE)
fprintf(stderr, "Error: queue_push failed on %s\n", hostname);
pthread_mutex_unlock(&locks[0]);
}
hostname = (char*) malloc(STRING_SIZE);
}
printf("%d\n", queue_is_full(&q));
free(hostname);
fclose(input);
pthread_exit(NULL);
}
void* resolvers(void* output_file)
{
char* hostname;
char ipstr[INET6_ADDRSTRLEN];
FILE* output = output_file;
int is_empty = queue_is_empty(&q);
//while(!queue_is_empty(&q) && !requestors_finished)
while((!requestors_finished) || (!is_empty))
{
while(is_empty)
usleep((rand()%100));
pthread_mutex_lock(&locks[0]);
hostname = (char*) queue_pop(&q);
pthread_mutex_unlock(&locks[0]);
if(dnslookup(hostname, ipstr, sizeof(ipstr)) == UTIL_FAILURE)
{
fprintf(stderr, "DNSlookup error: %s\n", hostname);
strncpy(ipstr, "", sizeof(ipstr));
}
pthread_mutex_lock(&locks[1]);
fprintf(output, "%s,%s\n", hostname, ipstr);
pthread_mutex_unlock(&locks[1]);
free(hostname);
is_empty = queue_is_empty(&q);
}
pthread_exit(NULL);
}
Although I'm not familiar with your "queue.h" library, you need to pay attention to the following:
When you check whether your queue is empty you are not acquiring the mutex, meaning that the following scenario might happen:
Some requestors thread checks for emptiness (let's call it thread1) and just before it executes pthread_mutex_lock(&locks[0]); (and after if(!queue_is_full(&q)) ) thread1 gets contex switched
Other requestors threads fill the queue up and when out thread1 finally gets hold of the mutex if will try to insert to the full queue. Now if your queue implementation crashes when one tries to insert more elements into an already full queue thread1 will never unlock the mutex and you'll have a deadlock.
Another scenario:
Some resolver thread runs first requestors_finished is initially 0 so (!requestors_finished) || (!is_empty) is initially true.
But because the queue is still empty is_empty is true.
This thread will reach while(is_empty) usleep((rand()%100)); and sleep forever, because you pthread_join this thread your program will never terminate because this value is never updated in the loop.
The general idea to remember is that when you access some resource that is not atomic and might be accessed by other threads you need to make sure you're the only one performing actions on this resource.
Using a mutex is OK but you should consider that you cannot anticipate when will a context switch occur, so if you want to chech e.g whether the queue is empty you should do this while having the mutex locked and not unlock it until you're finished with it otherwise there's no guarantee that it'll stay empty when the next line executes.
You might also want to consider reading more about the consumer producer problem.
To help you know (and control) when the consumers (resolver) threads should run and when the producer threads produce you should consider using conditional variables.
Some misc. stuff:
pthread_t requestor_threads[argc - 2]; is using VLA and not in a good way - think what will happen if I give no parameters to your program. Either decide on some maximum and define it or create it dynamically after having checked the validity of the input.
IMHO the requestors threads should open the file themselves
There might be some more problems but start by fixing those.

Producer Consumer Multithreaded printf issues

I have written a program which simulates the producer consumer problem and I am running into a couple of issues. This was written using Win32 API.
I am using two semaphores full and empty to perform the counting for the buffer where items are stored. There is a mutex as well to control access to the critical section. I have two functions: one creates an item based on a simple calculation: threads * 1000000 + count, while the other consumes it.
The buffer has 10 spaces in it however the program should hopefully be able to work for different number of spaces and threads. The Producer thread goes through the buffer then starts over until the semaphore counts up to 10. I am running into two problems that I can't seem to find a solution too nor do I get many details in the debugger.
1) The commented part which has the printf() function crashes the thread every single time. Nothing ever gets printed to console. I have tried using just a string as well with no other variables being outputted. No success. I found documentation that printf() can run into trouble when used in a multithreaded environment however in this case it is within the critical section and it crashes on the first try. How can I print that information to console?
2) When I remove the print statements and run the code the threads still crash at different points every time. I can't figure out why. The producer thread is supposed to wait for the empty semaphore and the mutex, put the item in, then increase the count for the full semaphore (signifying an item has been added). When it reaches 10 it should stop. The Consumer thread waits for the full semaphore and the mutex, removes an item, then increases the count for the empty semaphore. Is there something in the way I've written it that is causing these thread exits?
This is what I get:
The program '[5348] OperatingSystem.exe' has exited with code 0 (0x0).
#include<stdio.h>
#include<windows.h>
#include<ctype.h>
#include<tchar.h>
#include<strsafe.h>
#include<conio.h>
#include<time.h>
#define threads 1
#define MAX 10
typedef struct objects {
HANDLE empty;
HANDLE full;
HANDLE mutex;
int buffer[10];
};
struct objects data;
DWORD WINAPI Producers(LPVOID lpParam){
int count = 0;
int item;
while (TRUE){
if (data.buffer[count] == 0){
WaitForSingleObject(data.empty, INFINITE);
WaitForSingleObject(data.mutex, INFINITE);
item = threads * 1000000 + count;
data.buffer[count] = item;
//printf("Producer has produced: %d", item);
ReleaseMutex(data.mutex);
ReleaseSemaphore(data.full, 1, NULL);
}
count++;
if (count == 10){ count = 0; }
};
}
DWORD WINAPI Consumers(LPVOID lpParam){
int count = 0;
while (TRUE){
if (data.buffer[count] != 0){
WaitForSingleObject(data.full, INFINITE);
WaitForSingleObject(data.mutex, INFINITE);
//printf("Consumer has consummed: %d", data.buffer[count]);
data.buffer[count] = 0;
ReleaseMutex(data.mutex);
ReleaseSemaphore(data.empty, 1, NULL);
}
count++;
if (count == 10){ count = 0; }
};
}
int main(int argc, char *argv[]) {
struct objects data;
LONG initialCount = 0;
LONG maxCount = 10;
data.empty = CreateSemaphore(NULL, maxCount, maxCount, NULL);
data.full = CreateSemaphore(NULL, initialCount, maxCount, NULL);
data.mutex = CreateMutex(NULL, FALSE, NULL);
DWORD ConsumerId[threads];
HANDLE ConsumerThread[threads];
DWORD ProducerId[threads];
HANDLE ProducerThread[threads];
for (int i = 0; i < threads; i++){
ProducerThread[i] = CreateThread(
NULL,
0,
Producers,
NULL,
0,
&ProducerId[i]);
ConsumerThread[i] = CreateThread(
NULL,
0,
Consumers,
NULL,
0,
&ConsumerId[i]);
}
}

threads have the same id

I learn threads. I have read that thread terminates after it is out of a function (that is passed as parameter to pthread_create function).
So I create threads in the loop, they are executed and afterwards they are terminated.
(sorry for some long code)
But when I call a function pthread_create, new threads get the same ids. Why?
struct data {
FILE *f;
};
void *read_line_of_file(void *gdata) {
pthread_mutex_lock(&g_count_mutex); // only one thread can work with file,
//doing so we block other threads from accessing it
data *ldata = (data *) gdata;
char line[80];
int ret_val =fscanf(ldata->f,"%s",line);
pthread_mutex_unlock(&g_count_mutex); // allow other threads to access it
if (ret_val != EOF)
printf("%s %lu\n ", line, pthread_self());
// some time consuming operations, while they are being executed by one thread,
// other threads are not influenced by it (if there are executed on different cores)
volatile int a=8;
for (int i=0;i <10000;i++ )
for (int i=0;i <10000;i++ ) {
a=a/7+i;
}
if (ret_val == EOF) // here thread ends
pthread_exit((void *)1);
pthread_exit((void *)0);
}
int main() {
int kNumber_of_threads=3, val=0;
pthread_t threads[kNumber_of_threads];
int ret_val_from_thread=0;
data mydata;
mydata.f = fopen("data.txt","r");
if ( mydata.f == NULL) {
printf("file is not found\n");
return 0;
}
for( ; val != 1 ;) {
// THIS IS THAT PLACE, IDs are the same (according to the number of processes),
// I expected them to be changing..
for(int i=0; i<kNumber_of_threads; i++) {
pthread_create(&threads[i],NULL,read_line_of_file, &mydata);
}
for(int i=0; i<kNumber_of_threads; i++) {
pthread_join(threads[i], (void **) &ret_val_from_thread);
if (ret_val_from_thread != 0)
val = ret_val_from_thread;
}
printf(" next %d\n",val);
}
printf("work is finished\n");
fclose(mydata.f);
return 0;
}
as result, I see that id of threads are not being changed:
I wonder, are new threads really created?
Thanks in advance!
Thread IDs are only guaranteed to be different among currently running threads. If you destroy a thread and create a new one, it may well be created with a previously used thread ID.

Resources