Passing structures in pthread - c

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.

Related

Pass variable into pthread_create function

I'm building a multi-threaded network chat program, but I can't figure out how to pass variables into pthread_create.
I have the following line of code that creates a thread:
pthread_create(&thread, NULL, receive, (void *) socket_fd);
My receive function looks like this:
void * receive(void * socket) {
int socket_fd, response;
char message[MESSAGE_BUFFER];
socket_fd = (int) socket;
while(true) {
response = recvfrom(socket_fd, message, MESSAGE_BUFFER, 0, NULL, NULL);
if (response) {
printf("\nServer> %s", message);
printf("%s", prompt);
}
}
}
How can I pass a prompt variable into this receive function, when calling receive in pthread_create?
You can pack all of the data you want to pass to your thread on creation in a single struct and pass its pointer through the last parameter of pthread_create. in short:
define a struct:
typedef struct{
char* prompt;
int socket;
} thread_data;
and then call pthread_create:
thread_data data;
// place code here to fill in the struct members...
pthread_create(&thread, NULL, receive, (void *) &data);
in your receive function:
void * receive(void * threadData) {
int socket_fd, response;
char message[MESSAGE_BUFFER];
thread_data* pData = (thread_data*)threadData;
socket_fd = pData->socket;
char* prompt = pData->prompt;
while(true) {
response = recvfrom(socket_fd, message, MESSAGE_BUFFER, 0, NULL, NULL);
if (response) {
printf("\nServer> %s", message);
printf("%s", prompt);
}
}
}
Hope this helps.

implementing and testing thread_create function

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);

Using a String array in a thread function

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
}

Accessing the return value using pthread_exit()

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
...
}

c, creating thread and thread function

I created dispatch_queue_thread_t struct in the headerfile.
This code assign the thread, task and queue to the dThread struct
dispatch_queue_thread_t *dThread;
dThread = (dispatch_queue_thread_t *) malloc(sizeof(dispatch_queue_thread_t));
pthread_t dispatcher_thread;
if(pthread_create(&dispatcher_thread, NULL, dispatcher_threadloop, (void *)dispatch_queue)){
perror("ERROR creating thread."); exit(EXIT_FAILURE);
}
dThread->task=NULL;
dThread->queue=dispatch_queue;
dThread->thread=dispatcher_thread;
This code is the thread functions for dispatcher_thread.
I need to use thread in dThread to check if there is any task is assigned to it and if not need to assign the task to it.
How do I do that?
Is my code correct?
void *dispatcher_threadloop(void * queue){
//thread loop of the dispatch thread- pass the tast to one of worker thread
dispatch_queue_t *dQueue;
dQueue=queue;
//can I do this?
dispatch_queue_thread_t *dThread;
printf("message-boss1");
dQueue = (dispatch_queue_t *)queue;
if (dQueue->HEAD!=NULL){
for(;;){
sem_wait(dQueue->queue_task_semaphore);
dThread->task = dQueue->HEAD;
dQueue->HEAD = dQueue->HEAD->next;
dQueue->HEAD->prev = NULL;
sem_post(dQueue->queue_task_semaphore);
//TODO
}
}
printf("message-boss2");
}
No. The dThread variable in dispatcher_threadloop() isn't initialised, so it's an error to dereference it.
It seems like you should be passing dThread to the thread function instead of dispatchQueue, as the thread function can obtain the latter from the former. Something like this (note that casting to and from void * is unnecessary):
dispatch_queue_thread_t *dThread;
dThread = malloc(sizeof *dThread);
dThread->task = NULL;
dThread->queue = dispatch_queue;
if (pthread_create(&dThread->thread, NULL, dispatcher_threadloop, dThread)) {
perror("ERROR creating thread.");
exit(EXIT_FAILURE);
}
then in the thread function:
void *dispatcher_threadloop(void *arg)
{
dispatch_queue_thread_t *dThread = arg;
dispatch_queue_t *dQueue = dThread->queue;
/* ... */

Resources