Technical Difficulties from on Top of the Mountain
  A little help reducing the opportunity for errors.
If there's two things I drill into the heads of those that work with me, its a couple of the Pragmatic Programmer rules: do not violate the principle of least astonishment, and don't repeat yourself (DRY).

Unfortunately, C++ constructors challenged the second one:

  class SampleBuffer
      SampleBuffer(int alen) ;
      SampleBuffer(char const * astring) ;

      std::unique_ptr    m_buffer ;
      int m_len ;
  } ;

  SampleBuffer::SampleBuffer(int alen) : m_len(alen)
    * m_buffer = new char[alen +1] ;
  SampleBuffer::SampleBuffer(char const * astring)
    int tmplen= strlen( astring) ;
    * m_buffer = new char[tmplen +1 ];
    m_len= tmplen ;
    strncpy( * m_buffer, astring, tmplen) ;

Either you lived with two copies of the initialization code, or you created a private init() function which you called from both constructors. Not ideal, but I never worked in a group large enough that I had to worry about someone trying to call init() other than in the constructor. Still, it could happen, and that would probably be bad.

In C++11 they added constructor chaining which have shown up in other languages like c sharp and java. So now the constructors can look like this:

  SampleBuffer::SampleBuffer(int alen) : m_len(alen)
    * m_buffer = new char[alen +1] ;
  SampleBuffer::SampleBuffer(char const * astring) : DRYBuffer(strlen(astring))
    strncpy( * m_buffer, astring, m_len) ;

Already an improvement, especially if you decide to change something like having m_len represent the size of the buffer including the null terminator (heaven help you tracking down that off by one error in the original with the two separate code paths).

Obviously this is just an example (only a small step above the other trivial examples out there), but I've done the init() thing before for non-trivial cases, and this will be a handy alternative.

Of course there's the issue of where you can use this, and where you can't. It looks like g++ 4.6 does not support this, but g++ 4.7 on works fine.

Labels: , ,

  Reaching back into the past
I started this blog about ten years ago. Mostly as a place to put the odd stories that my kids were too young to understand but might be interested in later. There's always strange things going on in the world, and in my life, so I had plenty to write about. The one thing I didn't understand when I got started though was how ephemeral the web is. Things you link to today are often gone tomorrow. This was especially true with images.

These days I make a copy of the image, but originally I linked straight to the source, and now my 2004 pages are filled with broken pictures. I went back to fix a couple that seem to be popular still, one pointing to a favorite cartoon from Ink Tank. The artist took his original site down after a while, moved to a different domain, and has put some of the cartoons back online, but still has hundreds to go through.

Luckily I remembered another way to grab the original: The Internet Wayback machine. Yes, there's a site where they scoop up the whole internet and keep it in deep storage so you can see what hairdoos and trendy outfits looked like back in 1999. Ok, maybe we don't need that, but I was able to locate the original page for my Master Geek page, and restore the cartoon.

And here's another fun one restored at InkTank's new home: Board Chow.
board chow

Actually though, don't try this unless you want to skip lunch.

Labels: , ,

  The Timescale of Standards.
I'm wading back into C++ right now for a couple of reasons.  My last project was a lot of perl, some javascript and some bare metal C; so maybe I just missed it a bit.  Also while C is the best language for getting processing done quickly, I like OO design for networking and over the years have built my own cross platform libraries for networking, data handling and threads that are really powerful.

I had read way back when that there was a new standard with things added to the libraries like cross platform threads.  I figured by now, I was behind the times, but I'd check it out and maybe update some of my libraries to work with the new standards way of doing things.  According to the history page at The History of C++, the standard work was started in 2005 and was referred to as C++0x as it was expected to be done long before 2010.  Hahaha.  You can see the reference still in the command line options for GCC 4.6.  But it took longer than expected, and the standard finally came out in 2011.

So now two years later, I 'm giving this stuff a test drive.  Short answer?  Its still sketchy.

My first test program should have been trivial, but I wanted each thread to have its own seeded random number generator.  The page for rand() & rand_r() say that they're really not that good and you should use drand48, but I wasn't getting even basic cross platform support for drand48_r and somewhere the include files called it out as deprecated.  Sigh.

On a wild guess, I went and took a look at the excellent documentation at cppreference, and while initially I did discover that the cpp library has a rand() function, its a mutex locked singleton.  Also not what I wanted.  But that at least got me to the random number generator section of the Numerics library, where with the help of some web resources, I figured out that I wanted to do:

typedef std::mt19937 rnd_type ;
std::uniform_int_distribution<rnd_type::result_type> urand(0, 400) ;

rnd_type m_rseed ;
m_rseed.seed( aseed) ;
int ival= urand( m_rseed) ;
There's also some samples where they mash that last part together with,
auto rnd= std::bind(urand, m_rseed) ;
int ival= rnd() ;
But that's getting a little too deep into the c++11 voodoo at this stage.

So my first example spun up and ran, and once I got the right compile settings for the different platforms, it was OK on cygwin, linux and windows.

Lets get a litte more complicated, add some non-determinism and let the threads try to coordinate with the new Atomic operations library.  This library is supposed to let you do read-modify-write operations on a single value without interruption by other threads, so that the state remains consistent without locks.

The threads, random numbers, and atomics all worked as advertised.  What bit me was the placeholder for actual work:  sleep.  Now I didn't want to sleep for seconds, I wanted to switch back and forth on the order of microseconds.  Hidden away in the Utilities library, is the chrono sub-section of the Date and time utilities.  With that you're supposed to be able to do:
std::chrono::microseconds    us( 1) ;
m_thread->sleep_for( urand( m_rseed) * us) ;
So what is missing from the pieces of this example?  All the chrono stuff seemed to be there, it was the sleep_for call.  On my six month old linux box, GCC 4.6 complained that "class std::thread has no member named sleep_for".  Cygwin was up to GCC 4.7, and should have supported it, but the package maintainers didn't compile libstdc++ with the option --enable-libstdcxx-time, and so it was conditional'd out, and Visual Studio 2012 was not having any of it either.

Strangely enough, a later example with a slightly different variation:

std::this_thread::sleep_for( urand( m_rseed) * us) ;
worked just fine, but I was still out on two out of three platforms.  I switched back to nanosleep() on the linux platforms, but was not finding anything helpful on windows, so I finally threw in a Sleep(0) on windows. That gave me the strangest behavior ever. Unlike the *nix version where I would see a very close count of cycles between two threads which were sleeping random amounts between consuming a global counter; I was getting imbalances on Windows of 40% consistently (like 364 to 136). Turns out that Sleep(0) is nothing at all like Sleep(1) and is its own private hack.  So I layered a dithering routine on top of Sleep like this:
int iadd ;
iadd += urand( m_rseed) ;
if ( iadd > 1000 ) { Sleep( 1) ;  iadd -= 1000 ; }
  else { Sleep( 0) ; }
and finally got reasonable results from the windows version.

With great trepidation, I copied the example for conditional_variable wait_for() straight from here, and except for having to use my own platform specific sleep() routine again, it worked just fine except for one little detail in Visual Studio.  The example used a macro for the atomic initializer:

std::atomic<int> i = ATOMIC_VAR_INIT(0);
Visual Studio was having none of it, but changing it to simply i = 0 worked just fine.

The release notes for GCC 4.8 say they no longer require platform developers to specify the --enable-libstdcxx-time, so when that comes out in the next few months (?), we'll give it a try again.  I have no idea what Visual Studio's plans are.

For now you can see my hacked up samples at github, along with other random test code.

Labels: , , ,

Life in the middle of nowhere, remote programming to try and support it, startups, children, and some tinkering when I get a chance.

January 2004 / February 2004 / March 2004 / April 2004 / May 2004 / June 2004 / July 2004 / August 2004 / September 2004 / October 2004 / November 2004 / December 2004 / January 2005 / February 2005 / March 2005 / April 2005 / May 2005 / June 2005 / July 2005 / August 2005 / September 2005 / October 2005 / November 2005 / December 2005 / January 2006 / February 2006 / March 2006 / April 2006 / May 2006 / June 2006 / July 2006 / August 2006 / September 2006 / October 2006 / November 2006 / December 2006 / January 2007 / February 2007 / March 2007 / April 2007 / June 2007 / July 2007 / August 2007 / September 2007 / October 2007 / November 2007 / December 2007 / January 2008 / May 2008 / June 2008 / August 2008 / February 2009 / August 2009 / February 2010 / February 2011 / March 2011 / October 2011 / March 2012 / July 2013 / August 2013 / September 2013 / October 2013 / November 2013 / December 2013 / December 2014 / February 2015 / March 2015 / July 2016 / September 2016 / December 2016 / April 2017 / June 2017 / July 2018 / November 2018 / January 2019 / February 2019 / April 2019 / December 2019 / March 2020 / April 2020 / May 2020 /

Paul Graham's Essays
You may not want to write in Lisp, but his advise on software, life and business is always worth listening to.
How to save the world
Dave Pollard working on changing the world .. one partially baked idea at a time.
Eric Snowdeal IV - born 15 weeks too soon, now living a normal baby life.
Land and Hold Short
The life of a pilot.

The best of?
Jan '04
The second best villain of all times.

Feb '04
Oops I dropped by satellite.
New Jets create excitement in the air.
The audience is not listening.

Mar '04
Neat chemicals you don't want to mess with.
The Lack of Practise Effect

Apr '04
Scramjets take to the air
Doing dangerous things in the fire.
The Real Way to get a job

May '04
Checking out cool tools (with the kids)
A master geek (Ink Tank flashback)
How to play with your kids

Powered by Blogger