Monday, May 01, 2006

RTSJ - The Real-Time Specification for Java

The latest Java News Brief by Don Busch is about RTSJ - The Real-Time Specification for Java. I had the opportunity to review and make comments before Don put the finishing touches on the article. Its a nice overview of Real-Time Java. Check it out.

Thursday, March 30, 2006

Command Prompt Here from Visual Studio

I use the explorer command prompt here capability all the time.

Today I was working in Visual Studio and thought wouldn't it be nice if you could just right click on a Solution Explorer file and select "Command Prompt Here". Well, I didn't find out how to do that, but I figured out how to do something even better. Add the command prompt as an External Tool.

Its rather easy to create an External Tool that opens a command prompt. Just select Tools.. External Tools...

Title: CommandPrompt
Command: c:\windows\system32\cmd.exe
Initial directory: $(ProjectDir)

Thats all there is to it. This will open a command prompt in the current project directory.

Now lets add one that opens a windows explorer to the project directory.

Title: Explorer
Command: explorer
Arguments: $(ProjectDir)

After you have created these external tools, you can then setup a shortcut or customize your menu to place them on the main menu.

Tuesday, February 21, 2006

Boost Training Opportunities In St. Louis

I'm still finishing up the course, but OCI has started advertising the class.

Boost is a quickly growing and widely utilized Open Source C++ collection of libraries that provide tomorrow's C++ today. Boost allows developers to more quickly develop high performance production ready tailored applications. Many of the libraries are either already part of the draft C++ Standards Committee's Library Technical Report (TR1) or are proposed for the upcoming TR2.

I'll be covering the following Boost libraries.

Boost Test Library
Boost Conversion Library
Boost Smart_ptr Library
Boost Container Library
Boost Bind Library
Boost Function Library
Boost Lambda Library
Boost Thread Library
Boost Regex Library
and more...

The first class is scheduled for April 26 - 28, 2006 with three more offerings in 2006. OCI offers onsite training as well.

Boost Training Class

Wednesday, December 07, 2005

Memory Management & Embedded Databases

There is an interesting article in the December, 2005 issue of Dr. Dobb's Journal about various memory management schemes in C++ written by the creators of eXtremeDB.

Tuesday, September 06, 2005

Threads Cannot be Implemented as a Library

Weiqi Gao has a post by the same name. I followed the post to the original source.

If you are a multi-threaded developer using C or C++, I think you will find this article very interesting.

Here are a few items that jumped out at me:

  • Given the following:

    thread 1 -> x = 1; r1 = y;
    thread 2 -> y = 1; r2 = x;

    Sequential consistent memory model would say that either r1 or r2 would have a value of 1 after execution. However the author of the article has this to say about sequential consistent memory, "In practice, it appears unlikely that such a restrictive memory model can be implemented with reasonable performance on conventional architectures." [Hans J. Boehm]

    It turns out that r1 == r2 == 0 is perfectly valid for the above.

  • Rewriting of adjacent data such that:

    struct { char a; char b; } x = { 'x', 'y' };

    thread 1 -> x.a = 'k';
    thread 2 -> x.b = 'h';

    It is valid for x.a == 'x' and x.b == 'y', because load and store can happen on different threads at the same time because they are in the same "memory location", where "memory location" is not defined.

  • Global data.

    Rewriting of adjacent memory even allows for adjacent global variables outside of a struct declaration. "Since linkers may, and commonly do, reorder globals, this implies that an update to any global variable may potentially read and rewrite any other global variable." [Hans J. Boehm]

    As I often say in my C++ classes, "never, ever, never use a global variable, and when you can't avoid it, still don't use one." Of course the real problem here is not global variables.


The paper goes on to discuss the importance of language support and clear specification of the memory model for correct multi-threaded programs. The author and others are working toward addressing these issues in the C++ standard similar to how they were addressed in Java.

Tuesday, July 12, 2005

Windows: How to capture stdout from a spawned child process

The below code is similar to my last post. However, it *does* work on Windows while the previous code only works on Unix.


std::string command = ...;

ACE_Process_Options opt;

// The child process to spawn.
opt.command_line(command.c_str());

// Define the two handles for the pipe,
// fd[0] will be used for stdin
// fd[1] will be used for stdout.
ACE_HANDLE fd[2];

// Create a pipe from the two file handles.
// Pipe between stdin and stdout.
// fd[0] <-> fd[1]
if (ACE_OS::pipe(fd) == -1)
ACE_DEBUG ((LM_ERROR, "%p\n", "pipe failed"));

// Set the stdin and stdout of the process to our file handles.
// fd[0] is used for stdin, fd[1] is used for stdout.
opt.set_handles(fd[0] /*stdin*/, fd[1] /*stdout*/);

// Spawn the child process.
ACE_Process proc;
if (proc.spawn(opt) == -1)
ACE_DEBUG ((LM_ERROR, "%p\n", "spawn failed"));

// Wait for the process to finish.
ACE_exitcode exitcode = 0;
proc.wait(&exitcode);

// After fork:
// fd[0] <-> fd[1] child
// fd'[0] <-> fd'[1] parent

// Need to close parent stdout or parent will be trying to read from it forever.
// With stdout closed parent will get EOF from the child so that the parent
// will know the child is done.
if (ACE_OS::close(fd[1]) == -1)
ACE_DEBUG ((LM_ERROR, "%p\n", "close stdout"));

// After close:
// fd[0] <-> fd[1] child
// fd'[0] <-> parent
// which leaves our (parent) stdin piped to child's stdout

// set_handles() dups the handles, so make sure they are released.
opt.release_handles();

// Read from parent's stdin, which is connected
// to the child's stdout.
std::string child_stdout;
const size_t BUFFSIZE = 1024;
char buf[BUFFSIZE + 1];
ssize_t n = 0;
while ((n = ACE_OS::read(fd[0], buf, BUFFSIZE)) > 0) {
buf[n] = 0;
child_stdout.append(buf, n);
}

// Close stdin.
if (ACE_OS::close(fd[0]) == -1)
ACE_DEBUG ((LM_ERROR, "%p\n", "close stdin"));

Friday, July 08, 2005

How to capture stdout from a spawned child process

A recent post to ace-users reminded me how hard it was for me to figure out how to capture stdout from a spawned child process in C++. After much research and trial and error, I came up with the following which uses ACE.

Update 7/12/2005: The below code does not work on Windows because Windows does not allow redirection of stdout/stderr to sockets which is what ACE_Pipe uses. See my next post for code that does work on Windows.


std::string command = ...;

ACE_Process_Options opt;

// The child process to spawn.
opt.command_line(command.c_str());

// Define the two handles for the pipe,
// fd[0] will be used for stdin
// fd[1] will be used for stdout.
ACE_HANDLE fd[2];

// Create a pipe from the two file handles.
// Pipe between stdin and stdout.
// fd[0] <-> fd[1]
ACE_Pipe pipe(fd);

// Set the stdin and stdout of the process to our file handles.
// fd[0] is used for stdin, fd[1] is used for stdout.
opt.set_handles(fd[0] /*stdin*/, fd[1] /*stdout*/);

// Spawn the child process.
ACE_Process proc;
if (proc.spawn(opt) == -1) ACE_DEBUG ((LM_ERROR, "%p\n", "spawn failed"));

// After fork:
// fd[0] <-> fd[1] child
// fd'[0] <-> fd'[1] parent

// Need to close parent stdout or parent will be trying to read from it forever.
// With stdout closed parent will get EOF from the child so that the parent
// will know the child is done.
if (ACE_OS::close(fd[1]) == -1) ACE_DEBUG ((LM_ERROR, "%p\n", "close stdout"));

// After close:
// fd[0] <-> fd[1] child
// fd'[0] <-> parent
// which leaves our (parent) stdin piped to child's stdout

// set_handles() dups the handles, so make sure they are released.
opt.release_handles();

// Read from parent's stdin, which is connected
// to the child's stdout.
std::string child_stdout;
const size_t BUFFSIZE = 1024;
char buf[BUFFSIZE + 1];
ssize_t n = 0;
while ((n = ACE_OS::read(fd[0], buf, BUFFSIZE)) > 0) {
buf[n] = 0;
child_stdout.append(buf, n);
}

ACE_exitcode exitcode = 0;
proc.wait(&exitcode);

// Close stdin.
if (ACE_OS::close(fd[0]) == -1) ACE_DEBUG ((LM_ERROR, "%p\n", "close stdin"));

// Close the pipe, pipe destructor does not close the pipe.
pipe.close();