I'm very new in C and Linux and English is not my mother language. Sorry in advance.
I'm working on a school project which is implementing thread api and I made the thread_create() function using clone().
The problem is that when I call thread_create(&tid1, NULL, (void *)Testcase1, 0); ,
it creates a new thread but TestCase1 also includes thread_create and it doesn't seem create another thread. Let me explain with my code below:
int foo(void* arg){
printf("Hii");
return 0;
}
int thread_create(thread_t *thread, thread_attr_t *attr, void *(*start_routine) (void *), void *arg)
{
void* stack;
stack= malloc( STACK_SIZE );
pid_t pid;
if( stack==0)
{
perror( "malloc : could not allocate stack" );
exit( 1 );
}
pid = clone( &foo ,( char* )stack+STACK_SIZE,SIGCHLD|CLONE_VM|CLONE_SIGHAND|CLONE_FS|CLONE_FILES,0 );
if(pid == -1)
{
perror("clone");
exit(2);
}
kill(pid, SIGSTOP);
Thread* newTCB = (Thread*)malloc(sizeof(Thread));
newTCB->stackSize = malloc(STACK_SIZE);
newTCB->pid = pid;
newTCB->status = THREAD_STATUS_READY;
rEnqueue(newTCB);
rPrintqueue();
free(stack);
printf("Child thread returned and stack freed.\n");
return 0;
}
And this is my test code below:
thread_create(&tid1, NULL, (void*)TestCase1, 0);
TestCase1() below:
int Tc1ThreadProc(int param)
{
int tid = 0;
int count = 0;
tid = thread_self();
count = 3;
while (count > 0)
{
/* sleep for 1 seconds */
sleep(2);
printf("Tc1ThreadProc: my thread id (%d), arg is (%d)\n", tid, param);
count--;
}
}
void TestCase1(void)
{
thread_t tid[TOTAL_THREAD_NUM];
thread_create(&tid[0], NULL, (void*)Tc1ThreadProc, (int*)1);
thread_create(&tid[1], NULL, (void*)Tc1ThreadProc, (int*)2);
thread_create(&tid[2], NULL, (void*)Tc1ThreadProc, (int*)3);
while(1){}
return ;
}
it's supposed to print "Tc1ThreadProc: my thread id (%d), arg is (%d)\n" 3 times but it prints only "Hii" which is because of the call to foo().
How do I fix this?
You pass pointer to function "TestCase1" as argument to "thread_create", but inside "thread_create" you don't use it at all:
thread_create(&tid1, NULL, (void*)TestCase1, 0);
You're calling "clone" syscall only with pointer to "foo" function.
From inside "thread_create" your "TestCase1" pointer is named "start_routine", so you need to call similar "clone" syscall, but instead pointer to "foo" you should pass pointer to "TestCase1". Something like that:
pid = clone( start_routine, (char*) stack + STACK_SIZE, SIGCHLD | CLONE_VM | CLONE_SIGHAND | CLONE_FS | CLONE_FILES, 0);
Related
I want to run Pthreads in c. i am comfortable with sending integer values to Pthread in c. But when I am passing the data structure to the thread, it is printing garbage values.
My code is as follows:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMBER_OF_THREADS 3
typedef struct MyStructure
{
int id;
char *myName;
}myst;
void *PrintHello(void *threadArgs)
{
myst *myPersonalSt;
myPersonalSt = (myst *) threadArgs;
printf("Thread %d and Name : %s \n", myPersonalSt->id ,
myPersonalSt->myName);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t threads[NUMBER_OF_THREADS];
long taskids[NUMBER_OF_THREADS];
int rc, t;
char myNameArray[NUMBER_OF_THREADS][100] = {"kp" , "kkp" , "ap"};
myst **mystArray;
mystArray = (myst **)malloc(NUMBER_OF_THREADS*sizeof(myst));
for(t=0;t<NUMBER_OF_THREADS;t++)
{
mystArray[t] = (myst *)calloc(1,sizeof(myst));
mystArray[t]->id = t+1;
mystArray[t]->myName = myNameArray[t];
}
for(t=0;t<NUMBER_OF_THREADS;t++) {
printf("Creating thread %d\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello,
(void *) mystArray);
if (rc) {
printf("ERROR; return code from
pthread_create() is %d\n", rc);
exit(-1);
}
}
for(t=0;t<NUMBER_OF_THREADS;t++) {
pthread_join(threads[t],NULL);
}
pthread_exit(NULL); // this takes an input parameter !
}
I was thinking that it was a problem with MALLOC (because it doesn't initialize memory allocated). So I used CALLOC , but the same problem occured.
rc = pthread_create(&threads[t], NULL, PrintHello,
(void *) mystArray);
You're missing the array index here, you mean mystArray + t.
On a side note: remove all these casts, they make the code hard to read. void * is generic and implicitly convertible in c.
This line is wrong:
rc = pthread_create(&threads[t], NULL, PrintHello,
(void *) mystArray);
Given how you're written the rest of the code, it should be:
rc = pthread_create(&threads[t], NULL, PrintHello,
(void *) ( mystArray[t] ) );
But the use of malloc()/calloc() is unnecessary:
myst mystArray[ NUMBER_OF_THREADS ];
memset( mystArray, 0, sizeof( mystArray ) );
...
rc = pthread_create(&threads[t], NULL, PrintHello,
(void *) &( mystArray[t] ) );
That will work without the malloc()/calloc().
I am trying to pass a structure when creating a thread but does not seem to work correctly!
Here is the structure:
struct analyse_data {
int verbose; //should be 1 or 0
};
Note that verbose can only be 1 or 0 and nothing else.
Here is the method being called (note it can be called multiple times by another method):
void dispatch(struct pcap_pkthdr *header, const unsigned char *packet,
int verbose) {
static bool thread_settings_initialised = false;
printf("Verbose: %d\n", verbose); //Prints 1 or 0
//Only run the first time dispatch method runs
if (thread_settings_initialised == false){
thread_settings_initialised = true;
//...
//Set mutex for the appropriate variables to remain thread safe
//...
//Set attr so threads are "Detached"
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//Set pthread_cond_init
//...
}
//Put parameters into a struct so can be sent in a thread
struct analyse_data data;
data.verbose = verbose;
//...
pthread_t tid;
printf("data.verbose: %d\n", data.verbose); //This prints 1 or 0
int rc = pthread_create( &tid, &attr, bar, (void *) &data);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
and this is the method thats being called by the thread:
void analyse(void *thread_data) {
struct analyse_data *data;
data = (struct analyse_data *) thread_data;
int verbose = data->verbose;
printf("Verbose = %d\n", verbose ); //Prints weird numbers like -547845...
}
As you can see from my comments, the value of verbose changes when being used inside the method. Why? What am I doing Wrong?
Many Thanks!
Update (thanks to JS1)
I updated my code to use a pointer:
void dispatch(struct pcap_pkthdr *header, const unsigned char *packet,
int verbose) {
static bool thread_settings_initialised = false;
printf("Verbose: %d\n", verbose); //Prints 1 or 0
//...
//Put parameters into a struct so can be sent in a thread
struct analyse_data *data = malloc(sizeof(struct analyse_data)); //NEW
data->verbose = verbose;
//...
pthread_t tid;
printf("data.verbose: %d\n", data.verbose); //This prints 1 or 0
int rc = pthread_create( &tid, &attr, bar, (void *) data);
//...
}
But now the analyse() method always outputs 0, even when verbose is 1!
You should not pass a stack variable to pthread_create. Notice that data is local to the function dispatch and will be out of scope when dispatch returns. You should instead either use malloc to allocate data, or use a static or global variable.
If you use the malloc method, it will look like this:
struct analyse_data *data = malloc(sizeof(struct analyse_data));
data->verbose = verbose;
int rc = pthread_create( &tid, &attr, bar, data);
You must remember to not call free on data from dispatch. The memory should "belong" to the thread, so you should eventually call free on data from the thread when you are done using the contents of data.
I'm having trouble debugging the following program I wrote. The idea is to have two seperate threads; one thread executes a 5 second countdown while the other waits for key input from the user. Whichever thread completes first should cancel the sibling thread and exit the program. However, the following code just hangs.
Any help would be appreciated, but I would be most grateful for an explanation as to the problem.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // For sleep()
#define NUM_THREADS 2
// The stuct to be passed as an argument to the countdown routine
typedef struct countdown_struct {
pthread_t *thread;
signed int num_secs;
} CountdownStruct;
// Struct for passing to the input wait routine
typedef struct wait_struct {
pthread_t *thread;
int *key;
} WaitStruct;
// Countdown routine; simply acts as a timer counting down
void * countdown(void *args)
{
CountdownStruct *cd_str = (CountdownStruct *)args;
signed int secs = cd_str->num_secs;
printf("Will use default setting in %d seconds...", secs);
while (secs >= 0)
{
sleep(1);
secs -= 1;
printf("Will use default setting in %d seconds...", secs);
}
// Cancel the other struct
pthread_cancel(*(cd_str->thread));
return NULL;
}
// Waits for the user to pass input through the tty
void * wait_for_input(void *args)
{
WaitStruct *wait_str = (WaitStruct *) args;
int c = 0;
do {
c = getchar();
} while (!(c == '1' || c == '2'));
*(wait_str->key) = c;
// Cancel the other thread
pthread_cancel(*(wait_str->thread));
return NULL;
}
int main(int argc, char **argv)
{
pthread_t wait_thread;
pthread_t countdown_thread;
pthread_attr_t attr;
int key=0;
long numMillis=5000;
int rc=0;
int status=0;
// Create the structs to be passe as paramaters to both routines
CountdownStruct *cd_str = (CountdownStruct *) malloc(sizeof(CountdownStruct));
if (cd_str == NULL)
{
printf("Couldn't create the countdown struct. Aborting...");
return -1;
}
cd_str->thread = &wait_thread;
cd_str->num_secs = 5;
WaitStruct *wait_str = (WaitStruct *) malloc(sizeof(WaitStruct));
if (wait_str == NULL)
{
printf("Couldn't create the iput wait struct. Aborting...");
return -1;
}
wait_str->thread = &countdown_thread;
wait_str->key = &key;
// Create the joinable attribute
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Create both threads
rc = pthread_create(&countdown_thread, &attr, countdown, (void *) cd_str);
if (rc) { printf("Error with the thread creation!"); exit(-1); }
rc = pthread_create(&wait_thread, &attr, wait_for_input, (void *) wait_str);
if (rc) { printf("Error with the thread creation!"); exit(-1); }
// Destroy the pthread_attribute
pthread_attr_destroy(&attr);
// now join on the threads and wait for main
pthread_join(wait_thread, NULL);
pthread_join(countdown_thread, NULL);
// Call pthread_exit
pthread_exit(NULL);
// Free the function structs
free(cd_str);
free(wait_str);
}
Getchar is not required to be a cancellation point. Select and pselect are. Even if you want to continue to use a countdown thread you could still provide a cancellation point in the opposing thread by use of select.
I had reasonable behavior with the following modified wait_for_input()
// Waits for the user to pass input through the tty
void * wait_for_input(void *args)
{
WaitStruct *wait_str = (WaitStruct *) args;
int c = 0;
fd_set readFds;
int numFds=0;
FD_ZERO(&readFds);
do {
struct timeval timeout={.tv_sec=8,.tv_usec=0};
/* select here is primarily to serve as a cancellation
* point. Though there is a possible race condition
* still between getchar() getting called right as the
* the timeout thread calls cancel.().
* Using the timeout option on select would at least
* cover that, but not done here while testing.
*******************************************************/
FD_ZERO(&readFds);
FD_SET(STDOUT_FILENO,&readFds);
numFds=select(STDOUT_FILENO+1,&readFds,NULL,NULL,&timeout);
if(numFds==0 )
{
/* must be timeout if no FD's selected */
break;
}
if(FD_ISSET(STDOUT_FILENO,&readFds))
{
printf("Only get here if key pressed\n");
c = getchar();
}
} while (!(c == '1' || c == '2'));
*(wait_str->key) = c;
// Cancel the other thread
pthread_cancel(*(wait_str->thread));
return NULL;
}
I'm trying to pass an array to thread function so that it has access to the array in the function. For the moment it just contains the name of the threads.
const char *a[2];
char *s = "Thread 1";
char *r = "Thread 2";
a[0] = s;
a[1] = r;
pthread_create(&t, NULL, oddhandler, (void *)a[0]);
pthread_create(&y, NULL, evenhandler, (void *)a[1]);
The intention is to write the create like this
pthread_create(&t, NULL, oddhandler, &a);
pthread_create(&y, NULL, evenhandler, &a);
How would I re-write this function to accommodate this change?
static void *
oddhandler(void *p)
{
char *q = (char *)p;
printf("%s is ready.\n", q);
sigset_t set;
int sig = SIGUSR1;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
while (1) {
/* Wait for SIGUSR1 */
sigwait(&set, &sig);
printf("%s received a SIGUSR1!\n", q);
}
return ((void *)NULL);
}
You could try coupling the thread id with the thread data :
typedef struct thread_info {
int thread_id; // different for every thread
void * thread_data; // the same for every thread
}
As in your example program, you could create one function, handler, and have threads adjust based on their id.
pthread_create(&(t[id], NULL, handler, &(info[i]));
void * handler(void * info) {
thread_info * myInfo = (thread_info *) info;
char *q = ((char *) myInfo->thread_data) + myInfo->thread_id;
// rest of function
}
I have done the following code.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
struct foo
{
int a;
int b;
};
void* thread_func1(void *arg)
{
struct foo *temp = (struct foo*)malloc(sizeof(struct foo));
temp->a = 10;
temp->b = 20;
pthread_exit(temp);
}
void* thread_func2(void *arg)
{
pthread_exit((void*)100);
}
int main()
{
pthread_t tid1, tid2;
int err;
struct foo *f;
void *ret;
err = pthread_create(&tid1, NULL, thread_func1, NULL);
err = err | pthread_create(&tid2, NULL, thread_func2, NULL);
if(err != 0)
{
perror("pthread_create()");
exit(-1);
}
err = pthread_join(tid1, (void**)&f);
if(err != 0 )
{
perror("pthread_join1");
exit(-1);
}
printf("a = %d, b = %d\n", f->a, f->b); //Line1
err = pthread_join(tid2, &ret);
if(err != 0 )
{
perror("pthread_join2");
exit(-1);
}
printf("ret = %d\n", *(int*)ret); //Line2
return 0;
}
I get segmentation fault on Line2. What is wrong with Line2
If i modify Line2 to
printf("ret = %d\n", (int)ret);
there is no segmentation fault and it prints the correct value(ie, 100). I do not understand why the modification works. I believe i have the wrong concept regarding the usage of double pointers. I would like to get it corrected.
What is the reason for the Segmentation fault and why the modification works?
That's because you are returning the actual integer, not a pointer, but you access it as a pointer.
You return one number from the thread. In the first thread, that number is a struct foo *. Therefore, if you say
pthread_join(tid1, &ret);
then ret will contain that pointer (which is not a double pointer).
Similarly in the second case, you are returning 100 even though you are looking at it as if it's a void *. Nevertheless, the value is still 100!
Therefore when you write
pthread_join(tid2, &ret);
ret will contain 100, which is not a pointer, but a mere integer. That is why you should also cast it to int.
The reason you got a segmentation fault is that you look at 100 as an int * and then try to dereference it.
pthread_exit((void*)100); causes integer 100 to become exit status of your thread. It just abuses type cast so that void* is its type.
If you want to retrieve this value, you will have to use same type cast abuse in main thread as well:
int ret;
err = pthread_join(tid2, (void**) &ret);
// here you can work with ret as with any other integer
I also suggest you to use return instead of pthread_exit. Also note that memory dynamically allocated by using malloc should be freed by calling free. And type cast of return value of malloc is redundant here, it can be omitted.
This question could also help you: Close a thread when done with it
Its because you're trying to dereferencce a pointer whose address is 100.
Instead of looking at the return value, why dont you pass in a pointer to what you want to assign in the thread_funcs? That is, use the "void *arg" arguments of thread_func1() and thread_func2()
Like this:
void* thread_func1(void *arg)
{
struct foo **fooPtrPtr = (struct foo**) arg;
*fooPtrPtr = (struct foo*)malloc(sizeof(struct foo));
...
}
void* thread_func2(void *arg)
{
int *intPtr = arg;
*intPtr = 100;
...
}
int main()
{
pthread_t tid1, tid2;
int err;
struct foo *f;
int ret;
err = pthread_create(&tid1, NULL, thread_func1, &f);
err = err | pthread_create(&tid2, NULL, thread_func2, &ret);
...
printf("a = %d, b = %d\n", f->a, f->b); //Line1
...
printf("ret = %d\n", ret); //Line2
...
}