The following code generates output:
Creating thread 0
Creating thread 1
Creating thread 2
Creating thread 3
Creating thread 4
while the same binary works fine on other linux machines.
anyone has a solution ? I compiled with gcc -pthread and icc -pthread,
both have the same problem.
/******************************************************************************
* FILE: hello.c
* DESCRIPTION:
* A "hello world" Pthreads program. Demonstrates thread creation and
* termination.
* AUTHOR: Blaise Barney
* LAST REVISED: 04/05/05
******************************************************************************/
#include
On Wednesday 25 May 2005 5:02 pm, Long Fei wrote:
The following code generates output: Creating thread 0 Creating thread 1 Creating thread 2 Creating thread 3 Creating thread 4
while the same binary works fine on other linux machines. anyone has a solution ? I compiled with gcc -pthread and icc -pthread, both have the same problem.
/************************************************************************ ****** * FILE: hello.c * DESCRIPTION: * A "hello world" Pthreads program. Demonstrates thread creation and * termination. * AUTHOR: Blaise Barney * LAST REVISED: 04/05/05 ************************************************************************* *****/ #include
#include #include #define NUM_THREADS 5
void *PrintHello(void *threadid) { int i = 0;
while (i < 10) { printf("\n%d: Hello World!\n", threadid); fflush(stdout); i ++; }
pthread_exit(NULL); }
int main(int argc, char *argv[]) { pthread_t threads[NUM_THREADS]; int rc, t; for(t=0;t
The bug is that you are exiting the main thread before any of the child
threads get to run. try replacing the pthread_exit(NULL) in main() with:
for(t=0;t
On Wed, 25 May 2005, Anders Johansson wrote:
On Wednesday 25 May 2005 23:14, Jerry Feldman wrote:
That is because you have a bug in your program.
That's not the only bug, it's not nice to cast an integer to (void *). It invokes unspecified behaviour, I'm pretty sure
That's not a bug. Perhaps it's not the best style (and in this
particular case, even that is debatable), but there's nothing
technically wrong with it. A void * must be able to hold the largest
pointer value, and since you can't pass anything larger than a single
pointer value in C, it's not a problem. Technically, he *could* pass
the /value/ of the /address/ of t, but t might change before the thread
is started, so this is a perfectly cromulant use of void *.
In the thread, I'd have re-cast the void * back to an int, but even this
use of it is not incorrect.
I will note that the program does not contain a return value, although
perhaps the exit statement (versus thread_exit) might make the compiler
happier.
Of course, I could be wrong, it's late, and it's been a long day.
--
Carpe diem - Seize the day.
Carp in denim - There's a fish in my pants!
Jon Nelson
On Thursday 26 May 2005 00:07, Jon Nelson wrote:
That's not a bug.
Yes it is
Perhaps it's not the best style (and in this particular case, even that is debatable), but there's nothing technically wrong with it.
Yes there is
A void * must be able to hold the largest pointer value, and since you can't pass anything larger than a single pointer value in C, it's not a problem.
First of all, what do you mean by this? You can pass entire structs by value in C. It's perhaps not advisable from a performance point of view, but that's another issue. Secondly, there is nothing to guarantee that a pointer is stored in any form suitable to hold an integer. There are platforms where pointers are complex structures not at all suitable for storing integers. It is also possible that a pointer is 32 bit while an integer is 64 bit. The only thing guaranteed by the standard is that short <= int <= long and that a char is 8 bits. Nothing else regarding size is guaranteed, certainly not an equality between sizeof(int) and sizeof(void *) On x86 platforms and some others, you are usually lucky when you do this, because a pointer happens to be an integer there. But it is not guaranteed by the standard. A compiler would be free to do whatever it pleases after such a case. It is known as undefined behaviour and it is most definitely a bug, even though it may work on a few popular platforms
Technically, he *could* pass the /value/ of the /address/ of t,
commonly known as a pointer, yes, you can cast (int *) to (void *)
On Thursday 26 May 2005 00:28, Anders Johansson wrote:
It is known as undefined behaviour
I'm sorry, this is wrong. It's not undefined, it's implementation defined. Which means a compiler is free to do anything it wants, as long as it's documented. But it's still wrong, bad, non-portable and ugly.
On Thu, 26 May 2005 00:28:17 +0200
Anders Johansson
First of all, what do you mean by this? You can pass entire structs by value in C. It's perhaps not advisable from a performance point of view, but that's another issue.
Secondly, there is nothing to guarantee that a pointer is stored in any form suitable to hold an integer. There are platforms where pointers are complex structures not at all suitable for storing integers. It is also possible that a pointer is 32 bit while an integer is 64 bit. The only thing guaranteed by the standard is that
short <= int <= long
and that a char is 8 bits. Nothing else regarding size is guaranteed, certainly not an equality between sizeof(int) and sizeof(void *) The C standard does NOT say that a char is 8 bits. It says that it must be at least 8 bits.
On x86 platforms and some others, you are usually lucky when you do this, because a pointer happens to be an integer there. But it is not guaranteed by the standard. A compiler would be free to do whatever it pleases after such a case. It is known as undefined behaviour and it is most definitely a bug, even though it may work on a few popular platforms
As I mentioned, it happens to be a common practice in pthread
programming to pass an int directly into the thread entry.
The prototype for a pthread start routine is:
void *functionname(void *);
The C language does permit the assignment of an integral to a pointer
and vice-versa, but truncation and/or unexpected sign extension can
occur. Theoretically you are correct that a pointer on a specific
system could be 32-bits and an int could be 64-bits and a long 128-
bits. There are no systems I know of where a pointer is smaller than a
long. (I suppose mixed model programming an an old 8086 class could
have a 16 bit pointer and a 32-bit int, but Linux does not run on that).
--
Jerry Feldman
On Thursday 26 May 2005 02:08, Jerry Feldman wrote:
The C standard does NOT say that a char is 8 bits. It says that it must be at least 8 bits.
Fair enough
As I mentioned, it happens to be a common practice in pthread programming to pass an int directly into the thread entry.
Many things have at various times been common practice. This does not make it right, or even good practice.
The prototype for a pthread start routine is: void *functionname(void *); The C language does permit the assignment of an integral to a pointer and vice-versa, but truncation and/or unexpected sign extension can occur.
Well, as I mentioned, it is implementation defined. Which means you are creating a program that is not guaranteed to be portable to other compilers. I didn't know gcc explicitly allowed this, I've never bothered to look at it. Frankly I see little point in doing it. It seems to me it only serves to make programs that much less readable. I'm trying to think of benefits, but so far they escape me
On Wednesday 25 May 2005 8:57 pm, Anders Johansson wrote:
Well, as I mentioned, it is implementation defined. Which means you are creating a program that is not guaranteed to be portable to other compilers. The C standard itself does not define the width of a pointer type, but there is a set of conventions that all Linux and Unix systems use: ILP32 is used on 32-bit systems that define the type int, long, and pointer to be 32 bits. On 64-bit systems, there is LP64. In this case, int is 32-bits, where both long and pointers are 64-bits. Note that Windows-64 uses LLP64 where ints and longs are 32-bits and pointers and long longs are 64 bits.
But, as you very correctly mentioned, assignment of an integral to a pointer
and vice-versa is not a good programming practice. In the posted thread
example, there are 3 problems:
1. The premature exit of the main thread which causes an erroneous result on
Linux 2.6 kernel.
2. The passing of an int into the thread argument. This is simply a
non-portable and bad practice.
3. The use of the argument within the thread uncasted in the printf. This
may cause erroneous results on a big-endian system because the %d printf
specification will take the first 32-bits. So, on a Solaris or HP-UX 64-bit
system, the thread number will print as 0 in this particular case.
void *PrintHello(void *threadid)
:
printf("\n%d: Hello World!\n", threadid);
This should be:
printf("\n%d: Hello World!\n", (int)threadid);
----------------------
A better solution might be to pass the argument in as a pointer to a struct:
/******************************************************************************
* FILE: hello.c
* DESCRIPTION:
* A "hello world" Pthreads program. Demonstrates thread creation and
* termination.
* AUTHOR: Blaise Barney
* LAST REVISED: 04/05/05
******************************************************************************/
#include
On Wed, 25 May 2005 23:32:22 +0200
Anders Johansson
On Wednesday 25 May 2005 23:14, Jerry Feldman wrote:
That is because you have a bug in your program.
That's not the only bug, it's not nice to cast an integer to (void *). It invokes unspecified behaviour, I'm pretty sure That is a routine behavior for passing an int or long into the thread.
--
Jerry Feldman
On Wednesday 25 May 2005 17:02, Long Fei wrote:
The following code generates output: Creating thread 0 Creating thread 1 Creating thread 2 Creating thread 3 Creating thread 4
while the same binary works fine on other linux machines. anyone has a solution ? I compiled with gcc -pthread and icc -pthread, both have the same problem.
What do you believe the correct output should be for the program?
On Wed, 25 May 2005 20:45:08 -0400
Synthetic Cartoonz
What do you believe the correct output should be for the program? The expected output after adding join should be as I have listed below on a single-processor system. The ordering could be different depending on the scheduling algorithms.
Creating thread 0
Creating thread 1
Creating thread 2
Creating thread 3
Creating thread 4
0: Hello World!
0: Hello World!
0: Hello World!
0: Hello World!
0: Hello World!
0: Hello World!
0: Hello World!
0: Hello World!
0: Hello World!
0: Hello World!
1: Hello World!
1: Hello World!
1: Hello World!
1: Hello World!
1: Hello World!
1: Hello World!
1: Hello World!
1: Hello World!
1: Hello World!
1: Hello World!
2: Hello World!
2: Hello World!
2: Hello World!
2: Hello World!
2: Hello World!
2: Hello World!
2: Hello World!
2: Hello World!
2: Hello World!
2: Hello World!
3: Hello World!
3: Hello World!
3: Hello World!
3: Hello World!
3: Hello World!
3: Hello World!
3: Hello World!
3: Hello World!
3: Hello World!
3: Hello World!
4: Hello World!
4: Hello World!
4: Hello World!
4: Hello World!
4: Hello World!
4: Hello World!
4: Hello World!
4: Hello World!
4: Hello World!
4: Hello World!
--
Jerry Feldman
participants (6)
-
Anders Johansson
-
Jerry Feldman
-
Jerry Feldman
-
Jon Nelson
-
Long Fei
-
Synthetic Cartoonz