|
Well, looks like you beat me to it! Funny - I could have sworn I was replying to your previous message, but your posting seemed to intervene and mess up the ... er ... thread...
Anyway, I do recommend beginthreadex if you are using anything in the standard library. And consider using static?
|
|
|
|
|
Sorry for jumping in on top of you. No excuses!
|
|
|
|
|
_beginthreadex is recommended, check the article in MSDN.
|
|
|
|
|
Well, actually you only have one function anyway - its the instance data that is duplicated. So, if one class spins many threads, you need locks on the data. If several instances spin one thread each (sort of begs the question) you're still time slicing the same code. Static local vars would be a problem.
But to the interesting stuff - here's some code I've been playing with.
I first tried to reproduce your code using CreateThread - but since I am using some std stuff here, _beginthread turned out to be a good deal safer, as it links with a 'thread safe' version of the runtime.
The code below should compile for both Borland CB4 and VC6. The only syntactical change I had to make was in the assignment to z.x. Borland complained that ThreadProc alone was ambiguous.
The call to _beginthread shows the same behavior for the this pointer - if NULL, an access violation occurs at runtime. If this , members are accessed transparently.
Don't know if this is a serindipitous side effect, as Mario suggests, or something we can rely on, but certainly is interesting.
Note that there are no locks here, and the calls to cout can get a bit mixed (moreso in debug).
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
class Fred {
private:
int m_nThreadCount;
union {
void (__cdecl Fred::*x )(void *);
void (__cdecl *y )(void *);
} z;
public:
void __cdecl ThreadProc(void*);
void StartThread();
Fred():m_nThreadCount(0){};
};
void Fred::ThreadProc(void* lpParam) {
++m_nThreadCount;
cout << "Hey its me Fred!" << " Count is " << m_nThreadCount << endl;
}
void Fred::StartThread() {
z.x = &Fred::ThreadProc;
_beginthread(z.y, 0, this);
cout << "Thread started..." << endl << flush;
}
int main(int argc, char* argv[])
{
cout << "Thread test!" << endl;
Fred fred;
fred.StartThread();
int x;
cin >> x;
return 0;
}
I guess the next step is to look at some registers and see whats going on. BTW you might want to use _beginthreadex . I wanted to keep things simple.
Lastly, it seems to me that if the union trick works, there must be a way to cast the pointer passed to _beginthread . Hmmm...
this certainly makes for an interesting thread though...
|
|
|
|
|
I'm surprised that what you've done works. _beginthread takes three parms:
address of the thread functions
stack size
arg list pointer
What you're doing is completly non portable: you're using the 'this' pointer as the arg list and praying that Borland compiler will put it into the correct register and fake it for you. If you look at what your lpParm value is and compare it to what was passed as 'this' in your beginthread, it will be probably the same, but what happens when you compile in release mode? Plus you're also taking into account the memory layout of the union on your compiler to be the same on all compilers; it may not, since you have two different data types - one the address to a non-class function, and one an address to a scoped class function. Bet this will puke in IA64 and maybe other compilers. Bet the Intel c++ compiler will go completly nuts on you with this code.
Simplest, portable solution:
class Fred
public:
static void _Thread(void*pThis) { Fred*pFred=(Fred*)pThis; pFred->ThreadFunc(); }
void ThreadFunc() { ;/*whatever*/ }
void StartThread() { _beginthread(&_Thread,0,this); }
};
Note that this is the same as a lot of the callback stuff you'll get from the SDK. Lot cleaner, simpler to understand & teach newbies, and a hell of a lot easier to maintain!
Just my two cents as always...
|
|
|
|
|
Yup - I agree.
Now try doing it without using a static member fn.
But it looks like we all agree at this point that this is not good code - I just found the union trick interesting.
BTW I ran the code in both release and debug under Borland and VC. It seems to be a prevalent disease, this bad this.
Cheers
T
|
|
|
|
|
Actually, using a static is not portable either. It will probably work with most compilers, but technically it's undefined functionality. The compiler vendor is allowed to implement static members any way it chooses, so long as they follow certain rules. The static trick works primarily because a static member has the same function signature as non-static member in most implementations.
To be portable, you should use a non-member function and use the parameter passed to the function as a pointer to the object, however this also means you won't be able to access private or protected members through that pointer.
|
|
|
|
|
Ah, but it is portable - see Inside the C++ Object Model (S. Lippman), pages 121-124. Static functions are managled internally into non-class functions. "Taking the address of a static memmber function always yields the value of its location in memory, that is, its address. Because the static function is without a this pointer, the type of its address is not a pointer to a class member function but the type of a nonmember pointer to function." Sadly, the ARM doesn't give more than a trivial explanation of static data and functions, other than they have "external linkage". What reference were you using for the undefiend functionality?
In any case, you can work around the private/protected problem like this:
void bogus(void *ptr) { ((Fred*)ptr)->publicBogus(); }
class Fred
{
public:
void publicBogus() { ; /* do the real work here */ }
};
|
|
|
|
|
You're confusing portable (as in conforming to the ANSI/ISO standard) with "it works" based on a common implementation. Inside the C++ Object model was written long before the standard (1996). IIRC he even states that what he writes is based on common implementations.
|
|
|
|
|
Thank you all for your input. My original unease was well justified. The code is a turkey. I will use your suggestions and chuck in a static member function and work my requirements around it.
It's certainly been an eye-opener!
|
|
|
|
|
Just as a final note, it looks like this union trick has been seen before.
Stroustrup addresses this form of type conversion using unions in appendix C, section 8.3, and trounces it as non-portable, for pretty much the reasons Todd gave.
It seems that unions are poor cousins in the world of C++. Originally, I think the point was to allow C coders to save space. C++ adds some stuff that make it hard to fully assimilate unions into the language - e.g. classes with non-default ctors or dtors or copy ctors cant be used in a union (which dtor would you call?). Aside from that restriction, I get the impression that C++ has to weaken type checking in order to accomodate unions, which would explain why the union got around the parameter type checking for the calls to CreateThread and _beginthread, where no cast could. The tagged union construct (e.g. VARIANT) seems to have its place, but maybe unions should be considered harmful in C++.
Ok. I'll go away now. Happy coding!
|
|
|
|
|
I see you've already recieved answers to your questions, but I thought I would just cover the basic reasons why this is the case.
In C++, member functions do not have the same function signature as a non-member function except (in most cases) when the member function is static. I say in most cases because this is a compiler dependant implementation issue and is undefined in the standard, however the logical way to implement it is the way most compilers do (including VC).
C++ member functions pass a hidden first parameter called "this". When you call an object, it's translated to a different syntax so that the real call looks as so:
object.func(); is really called this way:
class::func(class* const this); So in reality, all member functions are non-member functions that are namespace qualified and pass a hidden first parameter that allows the function to know where it's instance data is. Something else most people don't realize is that a function that's declared const, such as:
void dosomething(void) const; is called this way:
void class::dosomething(class const * const this); This means that if you manage to hoodwink the compiler into compiling a non-member function pointer into a member function pointer, you're going to corrupt the stack. It also explains why when you pass the object instance as the parameter to function, it instead allowed it to be used for "this"; a lucky hack that is bound to break eventually.
So, in closing. Member function pointers and non-member function pointers are not the same type, even if they look like it.
|
|
|
|
|
Yes. I found all this out the hard way by going into the VS disassembler and looking at the calls and the stack.
There are two issues here anyway: the fake union cast and external calls into member functions. After all the good advice from everyone here and checking up in Bjarne Stroustrup's (whew, I hope I spelt it right) book I think I will stick to the straight and narrow from now on. It's safer.
|
|
|
|
|
this macro comes with pure win32, not mfc
Please HELP
|
|
|
|
|
Go to the following address: J.M. Newcomer homepage. Or, even better, buy the definite Win32 SDK/GUI guide: "Win32 Programming" (J.M. Newcomer & Brent Rector). It is on Amazon at Win32 Programming. I'm reading this book every day and still isn't enough...
However, it isn't a very good idea to mix MFC with pure Win32 techniques (unless you are sure what you are doing). Keep the standard message routing as 'standard' as possible; if you're on MFC, use MFC; if you're on Win32 SDK, use SDK. The MFC does a lot of things for you, but you have to play almost always by his rules. Complete customization is, indeed, offered by SDK, but there you have to build your own message maps (it's not so hard, even in pure Win32 C programming). Read the book (also Jeffrey Richter's "Advanced Win32 Programming" contains useful samples, although this book is OS oriented, not especially GUI) and apply the advices.
|
|
|
|
|
Why OnSize() in window starts 3 three times?
|
|
|
|
|
Well, the reason is quite simple. Your window changes size three times.
When the window is created, it's initial size is 0,0,0,0. That's the first size change. The first thing the OS does is resize the window to the size you specify, or the default. Let's pretend that's 100,100,100,100. That's the second size change. Third, you are probably sizing the window yourself, causing the third size change.
|
|
|
|
|
How i can change or delete the (default)title which appear when i open some view in my mdi project?
where is the place for it?
thx.
|
|
|
|
|
SetWindowText("MY Title"); in the view class.
Christian
The content of this post is not necessarily the opinion of my yadda yadda yadda.
To understand recursion, we must first understand recursion.
|
|
|
|
|
How can I create an exe file when my program is running but I do not have any other files which my program will need. Its a bit like self-extracting exe files but not the same principle. I did see a program one day: you supply a normal txt file, it gives you an exe file with that txt file appended into it. Another is a trainer which creates an exe file after you gave it a few details but it doesn't use any other external files. What is more amazing is that when the product exe is run, it creates a dll.
How can I create this type of program?
Please reply.
|
|
|
|
|
I think some progs can contain binaries that were originally loaded as resouces - there's a trick or two to identifying their location and size, but it can be done. Search for installers - I think WDJ had an article on this a while back.
|
|
|
|
|
Hello all,
I'm using Nullsoft's SuperPimp installer (open source installer!) for a project that I created. It has some patch files for some source that was compiled using visual c++ 6. Can anyone tell me how to automatically install the patch files? They come with .txt extensions. What extension should they use and where should I put them? Thanks in advance.
--Tale
|
|
|
|
|
Hello all,
I'm using Nullsoft's SuperPimp installer (open source installer!) for a project that I created. It has some patch files for some source that was compiled using visual c++ 6. Can anyone tell me how to automatically install the patch files? They come with .txt extensions. What extension should they use and where should I put them? Thanks in advance.
--Tale
|
|
|
|
|
Hi, ive writtena little utility which i plan to release as freeware.
part of this utility will transfer some data between two computers connected over tcp/ip.
Its' a MFC / dialog box interface.
the problem is this:
if i DONT limit the data to about 1kb at a time, then the data does NOT get transferred correctly over the internet - so to transfer 1 meg, i gota break it up into 1000 parts and send them. which i think must make the operation pretty slow.
is this NORMAL? and what is a workaround if one exists?
i havnt testes the exaact limit of the size i can send, but i know its under 5kb.
any help would be much appreciated
thanks
John McGrath
tails_naf@yahoo.com
|
|
|
|
|
This is 'sort of kind of' normal.
You can 'send' up to the size of your sockets send buffer, but to a large extent, the actual data chunk that goes down the wire is determined by the max transmission unit (MTU). This is normally around 563 ? bytes for the internet. This is determined by a legacy of routers that couldn't handle larger packet sizes, and normal for a win9x system. If you exceed this limit with a send, the socket will fragment the packets. This causes some overhead processing to occur.
I've suspected in the past that this fragmentation can lead to problems when shutting down sockets etc, but this may just be my paranoia. Still, if I were to venture some advice, I'd say send in 512 (room for IP and TCP header left) byte chunks - I don't know if there is any more efficiency (other than conscripting some sort of proxy to do the sending) to be had.
|
|
|
|
|