1

And I have to create a thread inside a function, that is (the thread) in an infinite loop waiting for connections and accepting messages from another process (so, the thread is going to work as a tcp server), and whenever a message comes, it has to ¿use? or call or whatever the function that's passed as a parameter, to the function the thread is created in.

So this is the function header

 int init(void (*notif)(const char *, const char *),
            void (*parameter1)(const char *),
            void (*parameter2)(const char *));

So I've seen this post How do you pass a function as a parameter in C? and it kind of helps to get the idea but I'm completly unsure how would I do it inside a thread.

And the reason for that is because I have little to no experience with servers inside threads, I found this code which is really helpful https://gist.github.com/silv3rm00n/5821760

But the way it works, all of the code is in the function (so outside the thread) and the thread takes as the only parameter the socket used for connections. I've seen it used similar to this a few times already.

And then I doubt: does it make sense to put all of the code of the server inside the thread? Or it would make little sense and the thread would be too "heavy" and it would be better to fork in that case.

I'm sorry if the question is poorly worded or I'm not explaining myself properly, I have little experience with threads and 0 experience with this type of problems.

edit: this is all I've got so far but I'm missing something, it does not work:

void (*funcionParametroThread)(const char *, const char *);
funcionParametroThread=(*notif_evento)(const char *, const char *);
pthread_create(&thid, &atrib_th, tcp_server, funcionParametroThread);

I tried making it similar to this code that is an answer from the linked question above

int dosomethingwithchar(char a) { return 1; }
functiontype2 func2 = &dosomethingwithchar
int result = func2('a');
Community
  • 1
  • 1
keont
  • 653
  • 1
  • 9
  • 26

2 Answers2

2

(Keep in mind that I'm writing on the fly)

A thread (linux pthread) as normally this signature:

void * threadName(void *parms)

It's started by the function pthread_create that starts it passing parms.

typedef void * THFN_t(void *parms)

struct thStruct {
 volatile int a; //volatile because the value may change during inter-process!
 volatile int b;
 volatile int c;
};

void * thread(struct thStruct *k) 
{
    for(;;) {
       /* do your job */
    }

    pthread_exit(NULL);
}

int main(void) 
{
   struct thStruct s;

   s.a=1; //These structure will be passed to the thread
   s.b=2;
   s.c=3;

   pthread_attr_t attr;
    pthread_t thr;
   pthread_attr_init(attr);
    if (pthread_create(
                (pthread_t*)&thr,
                (pthread_attr_t*)&attr,
                (THFN_t *)thread, //The function above
                (void *)&s)) {
                     perror("Error");
                     return errno;
      }

      while(s.a!=0) { //Used to lock the main, but also to pass something to the thread!
         printf("Insert a number: ");
         scanf("%d",s.a);
      }
}

This is the skeleton that contains hints to explain you how to pass information to a running thread. Remember the volatile and remember that some changes may be executed as atomic (you might use mutex to change them in the correct way).

I understand you need to inform your thread that it has to call a function and you need this function be a parameter.

I hope this function will have a fixed number of parameter ... :)

We say that the function we will call will have this signature:

int fnname(int a, char *b);

Then we declare (I prefer so):

typedef int FNX(int a, char *b);

Then we insert in the structure thStruct an element that specifies a pointer to the function we want call.

struct thStruct {
 volatile int a; //volatile because the value may change during inter-process!
 volatile int b;
 volatile int c;
 volatile FNX * fn; //Function pointer
};

Now we need the function:

int functionX(int a, char *b)
{
   printf("%d %s\n",a,b);
}

Next step: In the main, where we have initialized the thStruct, we want signal what function the thread will be call when a specific event occurs (for example s.a becomes 5)

Ok:

we add:

s.fn=functionX;

Now we modify the thread:

void * thread(struct thStruct *k) 
{
    for(;;) {
       if (k->a==5) {
          k->fn(a,"Yeah!\n");
          k->a=4; //To avoid continue calling k->fn
       }
       sched_yield(); //To avoid useless use of CPU time
                      //(this thread does nothing and waits for nothing!)
    }

    pthread_exit(NULL);
}

Now, if the program doesn't contain errors, you may compile it (I think you may solve if errors occurs) and will run.

When it will ran, you may insert 5 when main asks you a number and the function functionX will be called!

How I said you, I've written this code on the fly to help you. It may contain errors, but it should be able to explain some basilar things you need. There's more, but I think this give you a good way!

This is the end!!! (The Doors)

Sir Jo Black
  • 2,024
  • 2
  • 15
  • 22
  • I'm reading and re-reading this because some things are a little complex but I think I'm slowly getting it, so even before you finish I wanted to say thanks! I'm already on it. – keont Apr 12 '15 at 14:59
  • If you have problems free to write me (sirjoblack@hotmail.com), but don't esagerate with my patience!!! :p – Sir Jo Black Apr 12 '15 at 15:15
  • One example: making a simile, instead of the number 5, it could be some number as the one accept gives when a connection arrives, and inside the thread I'd recv and send (as needed) and then call the funcion with the syntax you wrote, k->fn(a,"Yeah!\n"); – keont Apr 12 '15 at 15:20
  • Another problem I have understanding this is how to "free" the main from working. I want to move the load to the thread, in this case I understand it as the process is the one handling the info to the thread and then the thread operates and does whatever is needed (and after that it calls the function). So I have trouble with that aspect of the main being locked (in the sense that I do not know how to avoid it, if needed) – keont Apr 12 '15 at 15:28
  • Pay attention! If you overload the thread you make obtain bad result in acquiring data from the network! Then if the function to execute as reply to what received is hard and heavy its better another thread manages this reply! – Sir Jo Black Apr 12 '15 at 15:28
  • There's a lot of good stuff in here. It is better, though, if you write the thread function as `void * thread(void *data) { struct thStruct *k = data; …` because then you aren't obliged to use casts to hammer the pointer to function into the correct type for `pthread_create()`. Every single one of the casts in the call the `pthread_create()` should be unnecessary; three of the four already are unnecessary. – Jonathan Leffler Apr 12 '15 at 15:29
  • I'm also unhappy about the volatile stuff. That should not be necessary. The data passed to the thread function should be private to the thread function and should have a lifetime long enough that it won't be changed by the code that creates the function while the thread lives. Often, that means you allocate the space specifically for the thread; the thread might need to free the space before exiting if you allocated the space with `malloc()`. Note that if the function that calls `pthread_create()` returns, the parameter to `pthread_create()` should not be a local variable. – Jonathan Leffler Apr 12 '15 at 15:34
  • The volatile is fundamental, because you may have serious problem with the compiler optimization. The compiler doesn't understand that you may change some values in pieces of code that run concurrently . It's since 20 years that I listen to people saying: "I hate volatile" ... and then ... !!! – Sir Jo Black Apr 12 '15 at 15:35
  • Yes, all the resources allocated for the thread have to exist during the thread life, but all the parameters that may be changed by concurrent thread/process it's better be volatile and in a lot of cases mutex protected! But I want leave these experiments to you!!! :) Remember that if you use the elements of the structure for IPC (InterProcessCommunications) their contents change cuncurrently with the thread! But you may think to use semaphore and other IPC stuff :) – Sir Jo Black Apr 12 '15 at 15:44
  • For now I'm unemployed then I might have times to reply at your e-mail requests!!! But I don't guarantee you, I consider myself to be unemployed on vacation !!! : p – Sir Jo Black Apr 12 '15 at 15:51
  • This is all I've got so far but it does not work @SergioFormiggini: void (*funcionParametroThread)(const char *, const char *); funcionParametroThread=(*notif_evento)(const char *, const char *); pthread_create(&thid, &atrib_th, tcp_server, funcionParametroThread); as in, it doesnt compile. Mind helping me some more? – keont Apr 13 '15 at 15:47
0

What I've done based on the links given and the incredibly detailed post of Sergio Formiggini:

The function:

int init(void (*notif)(const char *, const char *),
        void (*parameter1)(const char *),
        void (*parameter2)(const char *));

inside that:

void (*funcionParametroThread)(const char *, const char *);
funcionParametroThread=&(*notif);

and to create the thread:

pthread_create(&thid, &atrib_th, tcp_server, funcionParametroThread);

And once inside the function I use for the thread (tcp_server):

void (*funcionParametroThread)(const char *, const char *);
    funcionParametroThread=arg;
    (*funcionParametroThread)(temaRecibido,valorRecibido);
keont
  • 653
  • 1
  • 9
  • 26