Search code examples
cgtk

Correct thread function typing for use with g_thread_new() in C language?


I have written a multi-threaded program that works, but throws warnings at compile-time.

The header file contains the definition of a struct which contains data, as well as the thread function prototype:

//=============main.h=============
// Main data structure definition
typedef struct _SPSData SPSData;
struct _SPSData {
  GtkWidget *main_window;
  GtkWidget *menubar1;
  GtkWidget *view;
  GtkWidget *parent;  // Pointer to parent that spawned an error. e.g., data->menubar1, data->main_window, or data->traceroute_window

  char *error_text;  // String to hold error messages.
  char *warning_text;  // String to hold warning messages.

  etc.
};

// Thread function prototype
int ipv4_send (SPSData *);

The thread function to be started by g_thread_new() looks like:

//==========ipv4_send.c=============
int ipv4_send (SPSData *data)
{ 
  
  some error detection
  if error {
    return (EXIT_FAILURE);
  }
  
  Send ipv4 stuff.

  return (EXIT_SUCCESS);
}

And there's a callback from the UI which invokes ipv4_send() via g_thread_new():

//==========callbacks.c=======
// Send packet(s)
int on_button1_clicked (GtkButton *button1, SPSData *data)
{
  (void) button1;  // This statement suppresses compiler warning about unused parameter.

  GThread *thread;

  // Spawn thread to send IPv4 packet(s).
  thread = g_thread_new ("ipv4_send", (GThreadFunc) ipv4_send, data);
  if (! thread) {
    fprintf (stderr, "Error: Unable to create new thread for ipv4_send() in on_button1_clicked().\n");
    exit (EXIT_FAILURE);
  }

  return (EXIT_SUCCESS);
}

On compilation, I receive the warning:

callbacks.c: In function ‘on_button1_clicked’:
callbacks.c:3846:41: warning: cast between incompatible function types from ‘int (*)(SPSData *)’ {aka ‘int (*)(struct _SPSData *)’} to ‘void * (*)(void *)’ [-Wcast-function-type]
 3846 |     thread = g_thread_new ("ipv4_send", (GThreadFunc) ipv4_send, data);

Should the thread function be defined as follows?

==========ipv4_send.c=============
int *ipv4_send (SPSData *data)
{
 etc.

with corresponding change to the prototype:

// Thread function prototype
int *ipv4_send (SPSData *);

I don't know how to implement that, as my return statements would be incorrect.

In summary, I don't know how to make my function conform to the expected GThreadFunc typing.


Solution

  • Here is the answer as I interpreted what Cheatah said in the comments. This works perfectly and the compiler is no longer throwing warnings.

    The header file contains the definition of a struct which contains data, as well as the thread function prototype:

    //=============main.h=============
    // Main data structure definition
    typedef struct _SPSData SPSData;
    struct _SPSData {
      GtkWidget *main_window;
      GtkWidget *menubar1;
      GtkWidget *view;
      GtkWidget *parent;  // Pointer to parent that spawned an error. e.g., data->menubar1, data->main_window, or data->traceroute_window
    
      char *error_text;  // String to hold error messages.
      char *warning_text;  // String to hold warning messages.
    
      etc.
    };
    
    // Thread function prototype (consistent with GThreadFunc).
    void * ipv4_send (void *);
    

    The thread function to be started by g_thread_new() looks like:

    //==========ipv4_send.c=============
    void *ipv4_send (void *pointer)
    { 
      struct _SPSData *data;
      data = (SPSData *) pointer;
      
      some error detection
      if error {
        return (pointer);
      }
      
      Send ipv4 stuff.
    
      return (pointer);
    }
    

    And there's a callback from the UI which invokes ipv4_send() via g_thread_new():

    //==========callbacks.c=======
    // Send packet(s)
    int on_button1_clicked (GtkButton *button1, SPSData *data)
    {
      (void) button1;  // This statement suppresses compiler warning about unused parameter.
    
      GThread *thread;
    
      // Spawn thread to send IPv4 packet(s).
      thread = g_thread_new ("ipv4_send", (GThreadFunc) ipv4_send, data);
      if (! thread) {
        fprintf (stderr, "Error: Unable to create new thread for ipv4_send() in on_button1_clicked().\n");
        exit (EXIT_FAILURE);
      }
    
      return (EXIT_SUCCESS);
    }
    

    Thank you, Cheatah!