Personal computing discussed

Moderators: renee, SecretSquirrel, just brew it!

 
Crayon Shin Chan
Minister of Gerbil Affairs
Topic Author
Posts: 2313
Joined: Fri Sep 06, 2002 11:14 am
Location: Malaysia
Contact:

ctime() returns the same value for different times

Thu Feb 12, 2015 12:39 am

I'm writing some code describing a parking lot with x parking spaces:
#include <iostream>
#include <iomanip> //for setprecision on cout
#include <ctime>
#include <unistd.h> //for sleep

using namespace std;

class ParkingSpace
{
public:
   ParkingSpace();
   ~ParkingSpace();
   void becomesTaken(void);
   void becomesFree(void);
   time_t start, end, elapsed_secs;
};
ParkingSpace::ParkingSpace(){}
ParkingSpace::~ParkingSpace(){}
void ParkingSpace::becomesTaken(void){
   cout << "somebody just parked" << endl;
   start=time(NULL);
}
void ParkingSpace::becomesFree(void){
   cout << "a space was freed" << endl;
   end=time(NULL);
   elapsed_secs=difftime(end, start);
}

class ParkingLot
{
   ParkingSpace parkingspacearray[3];
   double pricepersec;
   long double revenue;
   unsigned int revenue_cents;
public:
   ParkingLot();
   ~ParkingLot();
   void test(void);
   void calcrevenue(time_t);
   void askformoney(ParkingSpace);
};
ParkingLot::ParkingLot(void){pricepersec=132.25;}
ParkingLot::~ParkingLot(void){}
void ParkingLot::test(void){
   parkingspacearray[0].becomesTaken();
   sleep(2);
   parkingspacearray[0].becomesFree();
   calcrevenue(parkingspacearray[0].elapsed_secs);
   askformoney(parkingspacearray[0]);
}
void ParkingLot::calcrevenue(time_t elapsed_secs){
   revenue=elapsed_secs*pricepersec;
   revenue_cents=(int)(revenue*100);
}
void ParkingLot::askformoney(ParkingSpace spaceinquestion){
   char *start_str, *end_str;
   start_str = ctime(&spaceinquestion.start);
   end_str = ctime(&spaceinquestion.end);
   cout << "You used our services from/to " << endl << spaceinquestion.start << " " << start_str << spaceinquestion.end << " " << end_str << endl;
   cout << fixed << setprecision(2);
   cout << "So you owe us $" << (double) revenue_cents/100 << endl;
}
int main(void){
   ParkingLot building;
   building.test();
   return 0;
}


So this is what happens when I run it:
somebody just parked
a space was freed
You used our services from/to
1423719995 Thu Feb 12 13:46:37 2015
1423719997 Thu Feb 12 13:46:37 2015

So you owe us $264.50


Why are the start and end times the same? They should be 2 secs apart!
Mothership: FX-8350, 12GB DDR3, M5A99X EVO, MSI GTX 1070 Sea Hawk, Crucial MX500 500GB
Supply ship: [email protected], 12GB DDR3, M4A88TD-V EVO/USB3
Corsair: Thinkpad X230
 
NovusBogus
Graphmaster Gerbil
Posts: 1408
Joined: Sun Jan 06, 2013 12:37 am

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 2:18 am

I think you're counting in milliseconds, so you'd want sleep(2*1000);
 
Crayon Shin Chan
Minister of Gerbil Affairs
Topic Author
Posts: 2313
Joined: Fri Sep 06, 2002 11:14 am
Location: Malaysia
Contact:

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 2:22 am

No, that just makes it sleep for 2000 seconds. Besides, the start and end variables (which are time_t) are defined as the number of seconds elapsed since the epoch.

And i just tried 2*1000, and it's still sleeping.
Mothership: FX-8350, 12GB DDR3, M5A99X EVO, MSI GTX 1070 Sea Hawk, Crucial MX500 500GB
Supply ship: [email protected], 12GB DDR3, M4A88TD-V EVO/USB3
Corsair: Thinkpad X230
 
Flying Fox
Gerbil God
Posts: 25690
Joined: Mon May 24, 2004 2:19 am
Contact:

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 3:08 am

Not doing native code much these days, took me a bit of reading back and forth to figure out the problem.

This is what you get when you mix C and C++ without thinking carefully enough about side effects of real objects vs pointers.
ctime documentation wrote:
The returned value points to an internal array whose validity or value may be altered by any subsequent call to asctime or ctime.

This means that there is an internal buffer (usually a static one), which stores the conversion results. In your code, start_str and end_str are both pointing to the same internal buffer used for the result of ctime(). In this case the string is the result of your last ctime() call. A lot of Java/C# coders with not enough C/C++ experience make this mistake all the time, treating "char*" as some kind of "object" that is assumed to point to different object instances with multiple calls to the same function. A lot of C runtime functions do not allocate memory automatically for you.

One fix is to use more real C++ objects:
string start(ctime(&spaceInQuestion.start));  // string's ctor makes a copy of the result from ctime into its own buffer, per string object instance
string end(ctime(&spaceInQuestion.end));
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
 
Crayon Shin Chan
Minister of Gerbil Affairs
Topic Author
Posts: 2313
Joined: Fri Sep 06, 2002 11:14 am
Location: Malaysia
Contact:

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 3:24 am

That was it! Thanks a lot! I guess this is commonly done in C because memory was scarce back then...
Mothership: FX-8350, 12GB DDR3, M5A99X EVO, MSI GTX 1070 Sea Hawk, Crucial MX500 500GB
Supply ship: [email protected], 12GB DDR3, M4A88TD-V EVO/USB3
Corsair: Thinkpad X230
 
just brew it!
Administrator
Posts: 54500
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 7:38 am

Crayon Shin Chan wrote:
That was it! Thanks a lot! I guess this is commonly done in C because memory was scarce back then...

Also because there's no automatic garbage collection in the C runtime, since there's no way to reference count dynamically allocated objects in a language where pointers are treated as raw (and even untyped in the case of void*) memory addresses with no other bookkeeping meta-data. Allocating a new buffer each time would mean the caller needs to explicitly free the buffer after using the contents, or you end up with a memory leak.
Nostalgia isn't what it used to be.
 
Flatland_Spider
Graphmaster Gerbil
Posts: 1324
Joined: Mon Sep 13, 2004 8:33 pm

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 8:40 am

Crayon Shin Chan wrote:
I guess this is commonly done in C because memory was scarce back then...


C is can be described best as portable assembly.
 
notfred
Maximum Gerbil
Posts: 4610
Joined: Tue Aug 10, 2004 10:10 am
Location: Ottawa, Canada

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 8:46 am

Eww C++. I'd just strdup() the ctime() returned value and remember to free() them afterwards.
 
just brew it!
Administrator
Posts: 54500
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 10:03 am

notfred wrote:
Eww C++. I'd just strdup() the ctime() returned value and remember to free() them afterwards.

For functions like ctime() -- where there's a known maximum length on the returned value -- a local (stack) variable is a bit cleaner. But neither of these methods will save you in multithreaded code, since another thread could call ctime() and step on the string before the first thread has had a chance to make the copy. A better solution is ctime_r() or strftime().

FWIW the asctime() and ctime() family of functions is deprecated in recent versions of the POSIX specification, with strftime() suggested as the functional replacement.
Nostalgia isn't what it used to be.
 
Flying Fox
Gerbil God
Posts: 25690
Joined: Mon May 24, 2004 2:19 am
Contact:

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 12:05 pm

IMO, if you are writing in C then stay in C-land, with the burden of garbage collection resting solely on you the developer.

If you are in C++, stay with the C++ idioms like RAII and use real "objects" and do not mix too much C in there.

The suggestion of strdup/_strdup is similar to creating new std::string instances where a copy is immediately made.

I can also see why ctime is deprecated in favour of a function that requires the caller to supply the buffer. ctime with multithreading seems like a recipe for long debugging sessions and lots of pulled hairs. :o
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
 
just brew it!
Administrator
Posts: 54500
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 12:26 pm

Flying Fox wrote:
I can also see why ctime is deprecated in favour of a function that requires the caller to supply the buffer. ctime with multithreading seems like a recipe for long debugging sessions and lots of pulled hairs. :o

Indeed. And the window for getting "had" by threading issues only gets worse with multi-core processors. In fact, on a multi-core CPU it is not hard to imagine a scenario where both threads get neither the old or the new value, but a jumbled mix of the two. (Two cores enter the function more or less simultaneously; but due to the vagaries of cache hits/misses, DRAM contention, hyperthreading, etc. one or the other pulls ahead as they write their respective results to the unintentionally shared buffer.)
Nostalgia isn't what it used to be.
 
Flatland_Spider
Graphmaster Gerbil
Posts: 1324
Joined: Mon Sep 13, 2004 8:33 pm

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 8:41 pm

Then there is the school of thought that says forking should be used instead of threading.
 
duke_sandman
Gerbil
Posts: 23
Joined: Fri Sep 02, 2005 9:56 am
Location: Washington DC

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 9:44 pm

And this is why I lurk in these forums. I learned something new tonight, gentlemen. And that, folks, is a very good night.

Cheers!
 
just brew it!
Administrator
Posts: 54500
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: ctime() returns the same value for different times

Thu Feb 12, 2015 10:35 pm

Flatland_Spider wrote:
Then there is the school of thought that says forking should be used instead of threading.

There's a time and a place for both. When the tasks being performed are relatively simple and there are common data structures that need to be shared, threads get the job done without all the extra overhead of separate processes and explicit IPC mechanisms. Threads are also a reasonable way to port (or simulate) applications written for lightweight embedded OSes like VxWorks or µC/OS-II, using a desktop OS like Linux or Windows. The concept of a "task" used in these lightweight OSes tends to map pretty cleanly onto threads within a single process on a desktop OS.
Nostalgia isn't what it used to be.
 
notfred
Maximum Gerbil
Posts: 4610
Joined: Tue Aug 10, 2004 10:10 am
Location: Ottawa, Canada

Re: ctime() returns the same value for different times

Fri Feb 13, 2015 2:39 pm

And for the truely insane there is setjmp() and longjmp(). You haven't lived until you've tried debugging a program that uses setjmp() and longjmp() for it's own psuedo-threading - bonus points if it manages to schedule them across several real POSIX threads! :)
 
just brew it!
Administrator
Posts: 54500
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: ctime() returns the same value for different times

Fri Feb 13, 2015 2:55 pm

notfred wrote:
And for the truely insane there is setjmp() and longjmp(). You haven't lived until you've tried debugging a program that uses setjmp() and longjmp() for it's own psuedo-threading - bonus points if it manages to schedule them across several real POSIX threads! :)

I haven't just debugged code that does that... I've written it! (This was many years ago... does this mean I was insane back then? :lol:)

Took an existing scientific computation library running on "bare metal" nodes that didn't support any form of native threading or multi-tasking (there was no OS to speak of), and modified it with setjmp()/longjmp() to allow I/O operations from multiple "threads" to be coalesced. This allowed I/O overhead to be amortized across dozens or hundreds of data transfers. Prior to the modifications I/O overhead was killing performance of the library; on certain algorithms, performance improved several-fold after the change.
Nostalgia isn't what it used to be.
 
morphine
TR Staff
Posts: 11600
Joined: Fri Dec 27, 2002 8:51 pm
Location: Portugal (that's next to Spain)

Re: ctime() returns the same value for different times

Fri Feb 13, 2015 3:24 pm

This is appropriate here: The only true measure of code quality
There is a fixed amount of intelligence on the planet, and the population keeps growing :(
 
just brew it!
Administrator
Posts: 54500
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: ctime() returns the same value for different times

Fri Feb 13, 2015 8:54 pm

morphine wrote:
This is appropriate here: The only true measure of code quality

Indeed. The setjmp()/longjmp() functions are pretty much a "WTF?" moment by definiition! I know that was my reaction the first time I encountered them, then went and read the documentation (had to read it multiple times to let it sink in, then try it out in a test program to see if they really did what the documentation seemed to be saying).

For the non-C-developers here (or for C developers who have never encountered the bizarre animal that is setjmp()/longjmp()), these functions implement what's known as a "non-local goto". In a nutshell, you call setjmp(), passing it a pointer to a "jump buffer". The jump buffer gets populated with enough information to restore the CPU state (program counter, stack pointer, and any other machine registers which are normally preserved across function calls) to the point of the setjmp() call. Subsequently, any other function, anywhere else in the program, can call longjmp() with a pointer to the same jump buffer, and program execution will magically resume from the point of the original setjmp() call.

Yes, there are (or at least were, back before we had the fancy threading capabilities that modern OSes provide) legitimate uses for this. Yes, it makes for some rather obfuscated code. Yes, if not used with extreme care, it will cause the program to crash, or at least misbehave in strange and mysterious ways. And yes, unless you really know what you're doing, you are likely to cause random resource leaks in any code that uses dynamic resource allocation (a longjmp() will even bypass class destructors for stack-based objects in a C++ program, for example). Fun times! :lol:
Nostalgia isn't what it used to be.
 
Flying Fox
Gerbil God
Posts: 25690
Joined: Mon May 24, 2004 2:19 am
Contact:

Re: ctime() returns the same value for different times

Sat Feb 14, 2015 1:25 am

just brew it! wrote:
morphine wrote:
This is appropriate here: The only true measure of code quality

Indeed. The setjmp()/longjmp() functions are pretty much a "WTF?" moment by definiition! I know that was my reaction the first time I encountered them, then went and read the documentation (had to read it multiple times to let it sink in, then try it out in a test program to see if they really did what the documentation seemed to be saying).

For the non-C-developers here (or for C developers who have never encountered the bizarre animal that is setjmp()/longjmp()), these functions implement what's known as a "non-local goto". In a nutshell, you call setjmp(), passing it a pointer to a "jump buffer". The jump buffer gets populated with enough information to restore the CPU state (program counter, stack pointer, and any other machine registers which are normally preserved across function calls) to the point of the setjmp() call. Subsequently, any other function, anywhere else in the program, can call longjmp() with a pointer to the same jump buffer, and program execution will magically resume from the point of the original setjmp() call.

Yes, there are (or at least were, back before we had the fancy threading capabilities that modern OSes provide) legitimate uses for this. Yes, it makes for some rather obfuscated code. Yes, if not used with extreme care, it will cause the program to crash, or at least misbehave in strange and mysterious ways. And yes, unless you really know what you're doing, you are likely to cause random resource leaks in any code that uses dynamic resource allocation (a longjmp() will even bypass class destructors for stack-based objects in a C++ program, for example). Fun times! :lol:

I just classify those in the assembly bucket pile of black voodoo. :lol:

I don't work in the embedded world anymore (did one intern with that stuff, but I was still at the application level). So I guess I am already spoiled and lucky.
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
 
notfred
Maximum Gerbil
Posts: 4610
Joined: Tue Aug 10, 2004 10:10 am
Location: Ottawa, Canada

Re: ctime() returns the same value for different times

Sat Feb 14, 2015 9:52 am

For added "fun" you can build your own jump buffers (and stack) and longjmp() to them without having done a setjmp(). By that point you are wondering why you are working in C and not just using straight assembly language, and how long before the men in white coats are coming to take you away. :)
 
just brew it!
Administrator
Posts: 54500
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: ctime() returns the same value for different times

Sat Feb 14, 2015 10:08 am

Flying Fox wrote:
I just classify those in the assembly bucket pile of black voodoo. :lol:

Well, C really is effectively a "high level assembly language" given that it provides only a thin layer of abstraction over the underlying hardware. That's what enables most modern OS kernels to be written in it. :wink:

(And yes, that implies that C++ amounts to "object oriented assembly language". And at some level, I think this is why so many people hate C++ since that's a bit of an oxymoron.)
Nostalgia isn't what it used to be.

Who is online

Users browsing this forum: No registered users and 1 guest
GZIP: On