Multithreading in C language: [I'm asking for explanation] - c

Can please some one explain the output of the code below!
I was working with threads in C language, and caught my eye that sometimes the output of the programs is not totally one of my prediction.
So I tried to write this code to understand more..
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
void * threadfun(void *arg){
printf("Hello from thread id %ld\n",*(pthread_t*)arg);
return NULL;
}
int main (int argc, char *argv[]){
pthread_t tid;
void * (*fp)(void*) = &threadfun;
printf("The Main program. pid = %d.\n",getpid());
pthread_create(&tid, NULL,fp,(void*)&tid);
printf("%ld was the thread id.\n",tid);
//pthread_join(tid, NULL);
printf("ENd. \n");
return 0;
}
I comment out the join function on purpose.
The output of this code was sometimes something like this:
gcc (Debian 11.2.0-10) 11.2.0
└─$ gcc s1_LD_thread01.c -o out_s1_thread01 -lpthread
└─$ ./out_s1_thread01
The Main program. pid = 8683.
140305239197248 was the thread id.
ENd.
Hello from thread id 140305239197248
Hello from thread id 140305239197248
I am wondering why the created thread outputting two strings.!

Related

CTRL + C doesn't kill C script

I'm reading Operating Systems: Three Easy Pieces and I'm finding a problem is not mentioned in the book.
This is the C script:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
/*#include "common.h"*/
#include <unistd.h>
#include <assert.h>
int
main(int argc, char *argv[])
{
int *p = malloc(sizeof(int));
assert(p != NULL);
printf("(%d address pointed to by p: %p\n",
getpid(), p);
*p = 0;
while (1) {
sleep(1);
*p = *p +1;
printf("(%d) p: %d\n", getpid(), *p);
}
return 0;
}
It allocates some memory, prints out the address memory, puts the number 0 into it and finally loops to increment the value.
I compile it through gcc -o mem mem.c -Wall and I have no problem running it with ./mem, if I press CRTL+C it will stop:
But then problems come when I run the script twice in parallel with the command ./mem & ./mem, look at the GIF:
No matter how many times I try to kill the process the scripts keeps hammering.
How to kill my C which project?
Use fg to bring the backgrounded process to the foreground, then it will respond to Ctrl-C.
You can also use jobs to see a numbered list of backgrounded jobs, and kill %<number> to kill a specific job, e.g. kill %1.

Why is my thread function running twice?

#include <stdio.h>
#include <sys/wait.h>
#include <pthread.h>
void* runfunc(void* arguments){
printf("in run thread\n");
return NULL;
}
int main(void)
{
pthread_t pthread_id;
pthread_create(&pthread_id, NULL, runfunc, NULL);
printf("after pthread creation\n");
return 0;
}
$ gcc -pthread intro.c
$ ./a.out
after pthread creation
in run thread
in run thread
$ ./a.out
after pthread creation
$
There are 4 types of outputs for this program on linux.
"after pthread creation" -> this output can be easily understood as before thread execution process completes and exits and deletes all threads.
"after pthread creation
in " -> this output can also be understood as while process was exiting thread executed a little bit to print in
"in running thread
after pthread creation" -> this output can also be easily understood
"after pthread creation
in running thread
in running thread" -> now i don't get why am i getting "in running thread" 2 times instead of once.
Linux implementation of threads is considered.

can someone tell me what's wrong with my program using fork() system calls(Programming C)

In this program, I am trying to use fork() functions to create 6 child processes and execute executionnode() functions,but I feel there is something wrong in my output!
what happened to my code or system calls?
I have a program like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
int executionnode(int i);
int main(){
pid_t childpid;
int i;
int row=6;
for(i=0;i<row;i++)
{ childpid=fork();
if(childpid==0)
continue;
else if (childpid>0)
executionnode(i);
else {
perror("something wrong");
exit(1);
}
}
}
int executionnode(int i){
sleep(i);
printf("hello, I am process:%ld\n",(long)getpid());
char *execArgs[] = { "echo", "Hello, World!", NULL };
execvp("echo", execArgs);
}
Everytime when I run this program,the output is always like this in my Linux terminal:
/*
hello, I am process:3226
Hello, World!
lixx3527#tiandiao123:~/Desktop/pa1-release$ hello, I am process:3227
Hello, World!
hello, I am process:3228
Hello, World!
hello, I am process:3229
Hello, World!
hello, I am process:3230
Hello, World!
hello, I am process:3231
Hello, World!
*/
I find my output even didn't finish, which means my program's executions haven't been finished, but lixx3527#tiandiao123:~/Desktop/pa1-release$ has appeared in the terminal ahead of time.
what happened to my code or system calls?
can someone help me explain it? I mean why lixx3527#tiandiao123:~/Desktop/pa1-release$ appeared before the program finished its all the execution?
thank you!
The parent runs very quickly, forking children. Then it quits and the shell prints a prompt. Then the other children run and print data. It looks like one child is able to print before the shell prints a prompt, and the others don't. If you want the parent to wait for the children to finish, there is a function conveniently named wait that will do that.

Using pthreads and malloc

I asked a question Using sockets in multithread server yesterday. In this question I described segmentation fault under Solaris in multithreaded server. Now I have found the core of error and written code, that shortly demonstrates it:
#include <stdlib.h>
#include <pthread.h>
int main(int argc, char *argv[])
{
pthread_attr_t *attr;
attr = (pthread_attr_t *)malloc(sizeof(pthread_attr_t));
pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);
malloc(0);
malloc(0); //Segmentation fault there
return 0;
}
Second malloc crashes with Segmentation fault.
While this code executes normally:
#include <stdlib.h>
#include <pthread.h>
int main(int argc, char *argv[])
{
pthread_attr_t *attr;
attr = (pthread_attr_t *)malloc(sizeof(pthread_attr_t));
// pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);
malloc(0);
malloc(0);
return 0;
}
Could you please explain the reason of the error?
P.S.: I compile with gcc -pthreads -lpthread -D_REENTRANT keys.
From the docs on pthread_attr_setdetachstate():
The behavior is undefined if the value specified by the attr argument to pthread_attr_getdetachstate() or pthread_attr_setdetachstate() does not refer to an initialized thread attributes object.
It's possible that the pthread_attr_t object the attr argument points to contains a pointer to some state maintained by the pthreads library. If it hasn't been initialized, that pointer would be garbage so the pthread_attr_setdetachstate() call might corrupt the heap.
See the pthread_attr_init() function to see how to properly initialize the attributes object.

Ensure transactions all complete on SHUTDOWN hook...sample code check

I actually asked a similar question earlier at Correct way to shutdown C application to ensure CRITICAL sections completed? but wanted to start fresh and ask is anyone can see and FUNDAMENTAL issues with the following code.
I essentially whipped up a proof of concept, and it goes like this:
Main application launches a thread that needs to "process messages in a transaction"
When the user hits CTRL-C I need the application to run elegantly until the current thread transaction is complete
NOTE: Callbacks from the thread into the MAIN app is ESSENTIAL and I would like to know if this is "bad programming practice"....
The code is working from the output, here is a sample:
lynton#lynton ~/Desktop/ThreadTest $ ./main
Main program started
In thread testMainLoop
Transaction started in spawned thread
onBeginTransaction in main thread
onMessageArrived in main thread
onCommitTransaction in main thread
Transaction ended in spawned thread
Transaction started in spawned thread
onBeginTransaction in main thread
onMessageArrived in main thread
onCommitTransaction in main thread
Transaction ended in spawned thread
Transaction started in spawned thread
onBeginTransaction in main thread
onMessageArrived in main thread
onCommitTransaction in main thread
Transaction ended in spawned thread
^CIn shutdown hook...
Thread still running
listenForMessages loop completed in spawned thread
In onProcessingComplete in main thread
Exciting testMainLoop
All thread transactions complete
Main program exiting
lynton#lynton ~/Desktop/ThreadTest $
In the above you can see that the shutdown hook is initiated and the application ends gracefully...
The basis test code is as follows:
PLEASE take special note of the "(*onProcessingCompleteCallbackFunc)(TRUE);" call from the thread to the main application to say to the main application that the thread is 100% complete. The pthread_join did not seem to work as I needed it to here....
NOTE: The following is the SHARED LIB (libwmq_sender.so) that I created that is used by the main application.
wmq_sender.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define TRUE 0
#define FALSE 1
int wmq_sender_start();
int wmq_sender_stop();
void wmq_sender_registerOnBeginTransactionCallback(int (*callbackFunc)(char *tid));
void wmq_sender_registerOnCommitTransactionCallback(int (*callbackFunc)(char *tid));
void wmq_sender_registerOnMessageArrivedCallback(int (*callbackFunc)(char *tid, char *buffer, int size));
void wmq_sender_registerOnProcessingCompleteCallback(void (*callbackFunc)(int completeFlag));
int listenForMessages();
int (*onBeginTransactionCallbackFunc)(char *tid);
int (*onCommitTransactionCallbackFunc)(char *tid);
int (*onRollbackTransactionCallbackFunc)(char *tid);
int (*onMessageArrivedCallbackFunc)(char *tid, char *buffer, int size);
void (*onProcessingCompleteCallbackFunc)(int completeFlag);
int running;
int rc;
int transactionRunning;
wmq_sender.c
#include "wmq_sender.h"
int listenForMessages(){
char *uuid = NULL;;
char *buffer = NULL;
uuid = malloc(10 * sizeof(char));
strcpy(uuid, "1234567891");
buffer = malloc(11 * sizeof(char));
strcpy(buffer, "test_buffer");
while(running == TRUE){
printf("Transaction started in spawned thread\n");
transactionRunning = TRUE;
(*onBeginTransactionCallbackFunc)(uuid);
(*onMessageArrivedCallbackFunc)(uuid, buffer, 11);
(*onCommitTransactionCallbackFunc)(uuid);
transactionRunning = FALSE;
printf("Transaction ended in spawned thread\n");
sleep(2);
}
printf("listenForMessages loop completed in spawned thread\n");
free(uuid);
free(buffer);
(*onProcessingCompleteCallbackFunc)(TRUE);
return 0;
}
int wmq_sender_start(){
return listenForMessages();
}
int wmq_sender_stop(){
running = FALSE;
return 0;
}
void wmq_sender_registerOnBeginTransactionCallback(int (*callbackFunc)(char *tid)){
onBeginTransactionCallbackFunc = callbackFunc;
}
void wmq_sender_registerOnCommitTransactionCallback(int (*callbackFunc)(char *tid)){
onCommitTransactionCallbackFunc = callbackFunc;
}
void wmq_sender_registerOnMessageArrivedCallback(int (*callbackFunc)(char *tid, char *buffer, int size)){
onMessageArrivedCallbackFunc = callbackFunc;
}
void wmq_sender_registerOnProcessingCompleteCallback(void (*callbackFunc)(int completeFlag)){
onProcessingCompleteCallbackFunc = callbackFunc;
}
The following is the MAIN application that spawns the thread and shuts down gracefully etc.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <time.h>
#include "wmq_sender.h"
#define TRUE 0
#define FALSE 1
void *testMainLoop(void *arg);
void shutdownHook(int sig);
int main(int argc, char * argv[]);
int onBeginTransaction(char *tid);
int onCommitTransaction(char *tid);
int onMessageArrived(char *tid, char *buffer, int size);
void onProcessingComplete(int completeFlag);
pthread_t testThread;
int threadRunning;
int rc;
void *testMainLoop(void *arg){
printf("In thread testMainLoop\n");
wmq_sender_registerOnBeginTransactionCallback(onBeginTransaction);
wmq_sender_registerOnCommitTransactionCallback(onCommitTransaction);
wmq_sender_registerOnMessageArrivedCallback(onMessageArrived);
wmq_sender_registerOnProcessingCompleteCallback(onProcessingComplete);
threadRunning = TRUE;
rc = wmq_sender_start();
printf("Exciting testMainLoop\n");
}
void shutdownHook(int sig){
printf("In shutdown hook...\n");
rc = wmq_sender_stop();
while(threadRunning == TRUE){
printf("Thread still running\n");
sleep(2);
}
printf("All thread transactions complete\n");
}
void onProcessingComplete(int completeFlag){
printf("In onProcessingComplete in main thread\n");
threadRunning = FALSE;
}
int main(int argc, char * argv[]){
(void) signal(SIGINT, shutdownHook);
printf("Main program started\n");
rc = pthread_create(&testThread, NULL, testMainLoop, (void *)argv);
pthread_join(testThread, NULL);
printf("Main program exiting\n");
return 0;
}
int onBeginTransaction(char *tid){
printf("onBeginTransaction in main thread\n");
return 0;
}
int onCommitTransaction(char *tid){
printf("onCommitTransaction in main thread\n");
return 0;
}
int onMessageArrived(char *tid, char *buffer, int size){
printf("onMessageArrived in main thread\n");
return 0;
}
Compiling on my test machine is:
gcc -m64 -Wall -g -I./ -c ./main.c -o ./main.o
gcc -m64 -o ./main ./main.o -L./ -L/usr/lib -L/usr/local/lib -lpthread -lwmq_sender
gcc -m64 -Wall -g -c -I./ -I/usr/local/include/ -fPIC ./wmq_sender.c -o ./wmq_sender.o
gcc -shared -o ./libwmq_sender.so ./wmq_sender.o
export LD_LIBRARY_PATH="/home/lynton/Desktop/ThreadTest"
Do you see anything wrong with the way that I use CALLBACKS to tell the main application that the thread is complete etc?
Any help or advise would be great appreciated ;-)
Thanks
Lynton
You do realise that your callback functions are actually running on the thread don't you? As far as I can see, your main thread just creates another thread which does everything and then waits for it to finish. I don't see any point in creating the second thread at the moment.
Anyway, the other horrible problem you have is that your signal handler calls printf and sleep. I'm pretty sure printf is not safe to call in a signal handler and neither is sleep. Really all it should do is set a flag to say "terminating" and then return.
According to the C99 standard, you can't reliably assign to any static variable that isn't declared volatile sig_atomic_t or call any standard library function except abort(), _Exit() or signal() and the last with the same signal number that you received.

Resources