Frequently Asked Questions

Categories

Segmentation Faults in C++CSP2 Programs

Question: When I try to run my application in Windows I get a popup message that reads: "Unable to find the entry point for procedure CreateFiberEx on the dynamic link library KERNEL32.dll" What is wrong?

Answer: C++CSP2 requires Windows 2000 (with Service Pack 4) or later to run. If you are getting this message, it is because you are trying to run a C++CSP2 application on an earlier version of Windows. If the machine is Windows 2000, install service pack 4. If it is older than Windows 2000, you will need to upgrade to a more recent versions of Windows. Windows 2000 itself is seven years old at the time of writing, and Windows 98 and Me are even older (and less stable), so I don't consider this to be an onerous requirement.

Question: I get weird errors or segmentation faults when running C++CSP2 with an older kernel on Linux. The problem occurs when C++CSP2 performs a context switch.

Answer: Earlier Linux kernels sometimes had a problem with Pthreads combining with setjmp - Pthreads would store the thread identifier using the current stack (at its base?) and setjmp would change stacks and therefore change this value. Newer versions of the old LinuxThreads library, and the new Native POSIX Threading Library (NPTL) do not suffer this problem. I believe this problem can occur under these configurations:

However, I do not have a machine with old versions of this software to test this out. Certainly, the problem should not occur under a 2.6 kernel with a recent version of glibc that includes NPTL. To see if you are using the NPTL, run "getconf GNU_LIBPTHREAD_VERSION". If you do experience this problem, please contact me.

Question: I am experiencing strange segmentation faults/general protection faults during my application, either consistently or just on certain occasions. I suspect it is because of C++CSP2 - what could be wrong?

Answer: There are three categories of common misuses of C++CSP2 that are likely to be causing such problems.

The first (and simplest) is that you may have forgotten to call Start_CPPCSP() before your C++CSP2 code begins. Similarly, if you have started new threads manually, you will need to place a Start_CPPCSP() call in those threads before you use C++CSP2. This is done automatically if C++CSP2 starts the thread for you.

The second possibility is that certain C++CSP2 components, such as the Run functions and the Alternative class, take a list of pointers to objects (to processes, and guards, respectively) that they will delete once they finish. If your program keeps pointers to any of these objects, and either accesses them after they have been deleted, or tries to delete them itself, a segmentation fault will probably result. You should either stop deleting them yourself, or stop accessing them after you have "handed them over" to the Run/Alternative. In the case of guards, there is no practical use to accessing them. In the case of processes, you should use channels to communicate with the barrier rather than accessing the process directly to perform a function call or access data.

The third possibility is that a process is using communication primitives (or, if you are using shared data, then shared data) that have been deleted/fallen out of scope, usually because of their parent process. Consider the following code:

    {
        ScopedForking forking;
        ...
        {
            One2OneChannel<int> c,d;
            forking.fork (new Id<int>(c.reader(),d.writer()));
            ...
        }
        ... //MARKED SECTION!
    }

In the marked section, the channels "c" and "d" will have been deleted, as they have fallen out of scope. However, the Id process may not have finished. If the Id process tries to communicate on its channels after they have fallen out of scope, it will probably cause a segmentation fault.

One common mistake is to do something like the following:

    {
        ScopedForking forking;
        ...
        {
            One2OneChannel<int> c,d;
            Chanout<int> dIn(d.reader());
            forking.fork (new Id<int>(c.reader(),d.writer()));
            ...         
            dIn.poison();
        }
        ... 
    }

The user might assume that because they have poisoned the channel, the Id process will finish, and so the object can fall out of scope safely. However, C++CSP2 is, of course, concurrent! The parent process poisons the channel, but Id needs to wake up and detect this poison, and poison its other channels, all before the channel can drop out of scope. The only way to be sure that this has happened is to wait for the destruction of the ScopedForking object.

To avoid such problems, always make sure that the objects a process uses will not fall out of scope before the process will have finished. A good practice is to declare all the channels before the ScopedForking, so that the ScopedForking will be destroyed (and wait for its children to finish) before the channels are destroyed:

    {
        One2OneChannel<int> c,d;
        ...
        {
            ScopedForking forking;
            ...
            forking.fork (new Id<int>(c.reader(),d.writer()));
            ...         
        }
        ... 
    }

There is more discussion on this topic on the page about the Scoped Objects.

Library Design

Question: Specifying a stack size to the CSProcess/ThreadCSProcess constructor is annoying. Neither JCSP nor occam requires this, so why does C++CSP2?

Answer: This problems is not unique to C++CSP2, but it is one of the libraries that exposes this problem to the user if they wish to change it. As far as I understand it, Java effectively uses a default "large enough" stack size for each thread, which is what C++CSP2 does if you do not specify a stack size. Occam has the advantage that the compiler can work out the needed stack size, and it does not have dynamic allocation on the stack (no recursion, no local variables of unknown size) so it can use very small stacks that are known to be safe.

Question: You mention in various parts of the documentation that something has undefined behaviour. What exactly does this mean?

Answer: Usually the meaning of undefined behaviour is "your application will crash immediately or will behave strangely and crash eventually". Any time that something has undefined behaviour, it is because using it in that manner is an error, and usually one that cannot be detected simply or efficiently. In some circumstances, it may not cause a problem on a particular OS on a particular machine - but that does not mean it will always work, or that the behaviour will work on other systems. As you might expect, avoid undefined behaviour!

Parallelism

Question: All my procsses seem to stop when I make a blocking system call in one of them, as if the entire program is blocked. I thought C++CSP2 was supposed to be concurrent and parallel - what gives?

Answer: This situation can occur if you have started all your processes in the same thread (using RunInThisThread() or csp::ScopedForking::forkInThisThread()). When one process makes a blocking call, it blocks the whole thread. To avoid this happening, start your processes in other threads (using Run() or csp::ScopedForking::fork()).

Question: My program does not seem to be making use of multiple cores, even though I have multiple processes running in parallel. Why is that?

Answer: There are two reasons why your program may not be making full use of multiple cores when you expect it to. The first reason is the same answer as the question above; you may have started all your processes in the same thread. This would mean that they would all run in turn on a single core at a time, which would explain why multiple cores were not being used.

The second reason is that the processes may be interdependent such that they may not make full use of all the cores. Consider a Prefix and an Id process that formed a circuit. Only one of these processes would be running at once, while the other was forced to wait for a communication. This sort of tight dependency prevents both processes running all the time.

Question: I can't create more than around 2,000 or 3,000 processes on a 32-bit machine before I get an OutOfResourcesError thrown. Why is the limit so low, and how can I increase it? I want to be able to run many lightweight processes in parallel.

Answer: By default the stack size of a process is 1 megabyte. 2,000 processes would therefore require nearly 2 gigabytes of memory. On 32-bit systems, this represents the whole of the memory space available to a Windows program. On Linux the limit can be 2 gigabytes or 3 gigabytes (depending on your kernel configuration). The solution is to reduce the stack size of the process. Details about stack sizes can be found on the Processes page.

Question: You used to have the GNU pth library as an option for user-threading. Why is this not the case any more?

Answer: There are a couple of reasons. The library now uses atomic instructions, and these are only provided for x86 (and x86-64) processors. On these CPUs, GNU pth is not needed. If in future, C++CSP2 is again able to work on any processor (by providing alternative algorithms alongside all the atomic-based algorithms) then GNU pth might be worth looking at again - although I believe using GNU pth with Pthreads may be problematic/not possible. See the next question if you are interested in porting C++CSP2.

Library Compatibility and Porting

Question: You state that C++CSP2 works on x86 (and x86-64) compatible processors, on a specified range of versions of Windows and Linux (see the main page for more information on the latest compatibility). I want to run my application on that processor on another OS (such as Mac OS X, or one of the BSDs) or I want to run my application on a different processor (such as PowerPC). Can you port it to this system, or can I help you to do so?

Answer: There are three reasons why I might have not ported C++CSP2 to a particular system, which may apply:

Naturally, I often don't know if the third restriction applies until the second has been overcome. Ports to other OSes on x86 processors should usually be straightforward. I expect the BSDs to only require the adjustment of a few header includes, and OS X may be just as easy but I would not be as confident.

Other CPUs would probably encounter all three restrictions. On x86 processors on Linux, setjmp and longjmp can be used with a single assembly instruction to change the stack pointer, and all the necessary atomic instructions (such as atomic compare-and-swap) are definitely available. Other processors do threading differently such that a context switch becomes a difficult affair that would require learning the processor design. This is why porting to other CPUs is something I do not have the time to do. If you strongly wish to port to another CPU and know enough about the CPU design I would be happy to try to help, but I do not have the time and/or interest to learn the CPU design myself.

Question: Is C++CSP2 suitable for use in embedded systems?

Answer: Two main issues result from considering using C++CSP2 in embedded systems.

Firstly, C++CSP2 currently only runs on x86 and x86-64 CPUs. This means your embedded system will either need to be running such a CPU (which are relatively rare in an embedded context) or you will need to port C++CSP2 (in which case, see the answer to the above question).

Secondly, C++CSP2 uses relatively advanced C++ features. Some have had trouble in the past compiling it under custom C++ compilers created by hardware manufacturers because not all the advanced templating etc is available. However, if GCC (or a similar major compiler) can cross-compile to your desired platform then this should not be a problem.

An ancillary consideration is the memory use of C++CSP2. Because each process needs its own stack, running many processes requires many stacks, which requires much memory. Stack sizes can be customised, but you will need to consider whether the lowest stack size you can manage, multiplied by the number of processes you want to run, is less than the memory available to you in your embedded system.

Installation

Question: Boost is very annoying to install, because of its custom build process. Why do you have it as a dependency, and is there any way to make installing it easier?

Answer: As a C++ programmer, I find aspects of boost such as lexical_cast, list_of, tuples and many more features very useful. The build process is annoying, but you do not need to go through with it to compile C++CSP2. C++CSP2 does not use any of the features in the boost compiled libraries - it only needs the boost header files available to it. So just download the latest boost distribution from boost.org, unzip the boost directory in there into somewhere that lies on your include path, and C++CSP2 will compile.

Having said that, under Linux you may find that boost is available as a package in your package manager. Be warned that some distributions may have two versions of boost (e.g. boost and boost-devel) where one contains only the compiled libraries and the other has the libraries and header files. If this is still the case on your distribution then you'll need the development package.

Miscellaneous

Question: In the section DATA_TYPE requirements for a class you say the type "must support a default constructor" or "must support a copy constructor". I just want to use it with a primitive type, like int or float. Can I do so?

Answer: Yes. Primitive types effectively have a default and copy constructor and support assignment. Technically it's not a constructor, but it all pans out. I believe all templated DATA_TYPE objects in this library support all primitive types, unless there is an obvious special requirement (such as DATA_TYPE needing to be an iterator, or channel end).

My Question Is Not In Here

Question: Why is my question not on here?

Answer: If your question is not answered by the documentation or by this page, then feel free to contact me. My email address is: neil at twistedsquare dot com. If you do not receive an answer within a day or two, email me again to make sure it didn't get buried amongst other messages.


Generated on Mon Aug 20 12:24:28 2007 for C++CSP2 by  doxygen 1.4.7