C/pthreads programming help request

1,538 views
Skip to first unread message

Jamie White

unread,
Mar 1, 2013, 4:43:22 PM3/1/13
to notti...@googlegroups.com
Hi 

I could some help with this code...

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int main();
int a_thread(int arg);

int main()
{
    int thread_return, an_arg;
    pthread_t new_thread;

    char string[250];
    thread_return = pthread_create(new_thread, NULL, (&a_thread), an_arg);
}

int a_thread(*int arg) {
    printf("test");
}

Compiling it using Codeblocks/C

and getting this from CodeBlocks build messages, error is in bold:

/home/jamie/pthreads-practice/main.c||In function ‘main’:|
/home/jamie/pthreads-practice/main.c|14|warning: passing argument 1 of ‘pthread_create’ makes pointer from integer without a cast [enabled by default]|
/usr/include/pthread.h|225|note: expected ‘pthread_t * __restrict__’ but argument is of type ‘pthread_t’|
/home/jamie/pthreads-practice/main.c|14|warning: passing argument 3 of ‘pthread_create’ from incompatible pointer type [enabled by default]|
/usr/include/pthread.h|225|note: expected ‘void * (*)(void *)’ but argument is of type ‘int (*)(int)’|
/home/jamie/pthreads-practice/main.c|14|warning: passing argument 4 of ‘pthread_create’ makes pointer from integer without a cast [enabled by default]|
/usr/include/pthread.h|225|note: expected ‘void * __restrict__’ but argument is of type ‘int’|
/home/jamie/pthreads-practice/main.c|13|warning: unused variable ‘string’ [-Wunused-variable]|
/home/jamie/pthreads-practice/main.c|10|warning: variable ‘thread_return’ set but not used [-Wunused-but-set-variable]|
/home/jamie/pthreads-practice/main.c|17|error: expected declaration specifiers or ‘...’ before ‘*’ token|
/home/jamie/pthreads-practice/main.c||In function ‘main’:|
/home/jamie/pthreads-practice/main.c|15|warning: control reaches end of non-void function [-Wreturn-type]|
||=== Build finished: 4 errors, 6 warnings ===|

Clicking the error highlights this line (no 222) in pthreads.h

/* Create a new thread, starting with execution of START-ROUTINE
   getting passed ARG.  Creation attributed come from ATTR.  The new
   handle is stored in *NEWTHREAD.  */
extern int pthread_create (pthread_t *__restrict __newthread,
  __const pthread_attr_t *__restrict __attr,
  void *(*__start_routine) (void *),
  void *__restrict __arg) __THROWNL __nonnull ((1, 3));

Is anyone able to advise how to achieve the result I want, that is to say, create a new thread with pthreads.

Thanks in advance,
Jamie

Roger Light

unread,
Mar 1, 2013, 5:03:46 PM3/1/13
to notti...@googlegroups.com
Hi Jamie,

Try the below. The warnings are more useful in the first instance!

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int main();
int a_thread(int arg);

int main()
{
int thread_return, an_arg;
pthread_t new_thread;

char string[250];
thread_return = pthread_create(new_thread, NULL, (&a_thread), an_arg);
}

int a_thread(*int arg) {
printf("test");
}

Cheers,

Roger

jfowkes

unread,
Mar 1, 2013, 5:04:24 PM3/1/13
to notti...@googlegroups.com
You'll want to understand the difference between variables and pointers. The problems you're seeing are to do with what you're passing into the pthread_create function. They're not about threads specifically.

You've got lots of warnings about them as well as errors.

Try http://pw1.netcom.com/~tjensen/ptr/pointers.htm for a decent introduction to pointers.

Matthew Gates

unread,
Mar 1, 2013, 5:04:00 PM3/1/13
to Nottinghack
Well you've got a few different things going on there.

Look at the manual page for pthread_create and the argument types it
takes (split to different lines here for commenting):

int pthread_create(
/* arg 1 */ pthread_t *restrict thread,
/* arg 2 */ const pthread_attr_t *restrict attr,
/* arg 3 */ void *(*start_routine)(void *),
/* arg 4 */ void *restrict arg);

arg 1 is a pointer to a pthread_t. You passed by value. You need to
use the & (address of) operator to get a pointer.
arg 2. NULL is fine
arg 3 is a function pointer to a function which takes a void*
parameter and returns a void*, i.e. your thread execution function
should have this sort of prototype:

void* mythreadfunc(void* args);

arg 4 should be a void*, but you passed an integer by value.

Pointer syntax is confusing in C - especially for function pointers.
You'd do wel to do some exercises on it. Also understand what a void
pointer is and what it is used for (see also "casting").


Mouse
> --
> You received this message because you are subscribed to the Google Groups
> "Nottingham Hackspace - Nottinghack" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to nottinghack...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Michael Procter

unread,
Mar 1, 2013, 5:18:10 PM3/1/13
to notti...@googlegroups.com

The prototype for pthread_create (from the man page) is:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);

Things to note:
The first parameter is a pointer to pthread_t.
The start_routine prototype must look like:
void *start(void *)
The final parameter, arg, is a void*.

Bearing these in mind, here are the inline comments to fix your code:

On Fri, March 1, 2013 9:43 pm, Jamie White wrote:
> #include <stdio.h>
> #include <stdlib.h>
> #include <pthread.h>
>
> int main();
> int a_thread(int arg);

Wrong signature. You will need it to look like:
void *a_thread(void *varg);

>
> int main()
> {
> int thread_return, an_arg;
> pthread_t new_thread;
>
> char string[250];
> thread_return = pthread_create(new_thread, NULL, (&a_thread), an_arg);
OK - the 1st, 3rd and 4th args are wrong. Try this instead:

thread_return = pthread_create(&new_thread, // note pointer passed
NULL,
a_thread, // bare fn name decays to fn-ptr
&an_arg // ptr-to-int not bare int
);
> }
>
> int a_thread(*int arg) {
Now we need to fix this to match the prototype mentioned earlier:
void *a_thread(void *varg) {
int arg=*(int *)varg; // cast back to int* and dereference to get value
> printf("test");

Fn returning void * needs a return value. Let's keep it simple:
return 0;
> }


Finally, when you run this, you will find that it still doesn't work. You
should add a pthread_join call to the end of your main function, to wait
for the new thread to finish. Without it, you won't even wait for the
thread to start! Specifically:
pthread_join(new_thread, NULL);

Hope this helps,

Michael

Ian Dickinson

unread,
Mar 1, 2013, 5:41:04 PM3/1/13
to notti...@googlegroups.com
A similar, but slightly different solution ...


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int main();
int a_thread(int *arg);

int main()
{
    int thread_return, an_arg;
    pthread_t new_thread;

    an_arg=42;

    thread_return = pthread_create(&new_thread, NULL, (void * (*)(void *))&a_thread, &an_arg);

  pthread_join(new_thread, NULL);

}

int a_thread(int *arg)
{
    printf("test %d\n",*arg);
}

Jamie White

unread,
Mar 1, 2013, 6:29:31 PM3/1/13
to notti...@googlegroups.com
So glad I found you lot, the help here is very much appreciated.

I have got Ians examples working after sorting a few things with my build environment (like installing G++ and changing the build options on CodeBlocks!)

I got a rough understanding of pointers, but the examples here have to helped to clear up the understanding of exactly how to use them in particular when passing pointers to functions.

Just one other question for now, does anyone have any better solutions to avoiding stack overflows with threads than static analysis aided estimation of how big the stack could get and allocating each thread that amount of stack space + some spare.

This method of doing things seems a big recipes for bugs turning up later down the line without having ridiculously large stacks -especially if library updates cause a bigger stack to be required!

Thanks.
Jamie

Matthew Gates

unread,
Mar 1, 2013, 6:33:07 PM3/1/13
to Nottinghack
valgrind is a good tool to catch some coding errors, stack overflows
among them. It's output can be a little overwhelming to start with,
but it's a good tool.

Jamie White

unread,
Mar 1, 2013, 6:38:34 PM3/1/13
to notti...@googlegroups.com
Thanks, I shall take a look at it.

I haven't had stack overflow issues yet - haven't got far enough for that! There are an issue I am aware of though and keen to avoid.

Jamie

Roger Light

unread,
Mar 2, 2013, 5:16:31 AM3/2/13
to notti...@googlegroups.com
On Fri, Mar 1, 2013 at 10:41 PM, Ian Dickinson <i...@d1ckinson.com> wrote:
> A similar, but slightly different solution ...

I'm afraid I think this is an incorrect solution.

> int a_thread(int *arg);

> thread_return = pthread_create(&new_thread, NULL, (void * (*)(void *))&a_thread, &an_arg);

Casting the function like this isn't a good idea. Whilst the cast from
(int *) to (void *) for the argument is fine, the return value cast is
going to produce undefined results in the event that we try to use the
return value from a_thread() (which at the moment we've all ommitted,
another bad example to set :). It's also much less readable, for no
good reason.

Jamie - void pointers (void *) are fantastically useful because you
can cast them to anything with no problems. This makes them very
useful in the case where someone writing a library wants to offer the
possibility for the end developer the chance to pass some data in
without forcing them to match a particular data structure. This is one
of those examples. You know what data type you are passing as an_arg
to a_thread(), so you can cast it to that type within the function
without having to change the function definition. For example:

void *a_thread(void *arg)
{
struct my_data_type *data = (struct my_data_type *)arg;

or

float *f = (float *)arg;

or anything else.

Likewise the (void *) return value allows you to return anything you
want and then recast it to your data type when you retrieve it using
pthread_join(). You can't return memory that is local to the thread
though, so

void *a_thread(void *arg)
{
int a = 1;
return &a;
}

would produce undefined results.

I hope that clarifies things a bit more.

Cheers,

Roger

Ian Dickinson

unread,
Mar 2, 2013, 5:59:41 AM3/2/13
to notti...@googlegroups.com
Roger 
I agree with you completely, my complicated cast won't work if there was a return value and using the void *a_thread(void *arg); format is the proper and best way to declare the thread. I apologise for my hacking!
Ian

Reply all
Reply to author
Forward
0 new messages