UNIX programming examples

l.u. 18/12/2005

This page is for those who have no time (or are too lazy) to read lots of man pages. This is also a good starting point for getting introduced to some UNIX programming concepts and to UNIX IPC (that's Inter-Process Communication). The page covers several programming topics under UNIX in a practical fashion. Each topic has one or more full source code examples, for further clarification. Of course, when the tight details are needed, a complete reading of the appropriate man page is necessary.
While the Internet is rich with sites giving fragmentary examples on any particular subject, this page tries to wrap up more wholly information about the most common topics.

Subjects organization

The page is organized by subjects. One paragraph per subject, each paragraph having its notes, one summary and one or more source code examples. Notes are made of a brief intro on theory, and then infos about how UNIX implements the thing. Notes are meant not to be read by developers who already roughly know what they're searching about. There are summaries for that: they quickly list key aspects. POSIX conformance plays a big role here.
For every subject, some examples are reported in plain text/html. Examples are ready to be compiled an run on most OSes.
It is possible to download all the example sources in one package, and to download all the html highlighted sources in one package.

Usage of these sources and this page

Every source in this page, except where explicitly reported otherwise, has been invented, written and tested by myself. As far as I care, all these sources are public domain. In case you make conspicuous use of them, I like that you include some reference to this work in your credits.
About the rest of the contents in the page, please avoid copying it fully or in parts.
In general, if you found this page useful, consider including a link to it somewhere on the web. This will make the page more easily accessible from search engines for others too.
Any comment or different feedback is welcome, just follow the link for the contact page in the top, right of this document.
I would like to thank Roberto Farina, who encouraged this work and gave me the possibility to carry it out in spite of the choking engagements in university.

General topics on UNIX programming

The following entries cover some general programming topics under UNIX:

Interprocess communication / UNIX IPC programming

The following entries cover topics specific to Inter-process communication mechanisms under UNIX:

Regular expressions


Notes:
In the language theory, Regular Expressions are a metalanguage: a (formal) language to describe languages. Regular expressions (RE) can only describe the family of regular languages. Regular languages comprehend a small set of very simple languages whose properties are leftover. Talking about computers, RE refers to the language used for driving parser programs for recognizing strings. Recognize some text means verify it satisfies the properties expressed by the regular expression.
RE define a set of special characters whose meaning is shown below. Any character out of that list is matched as-is on the string against which you check the rule. The full RE is obtained by concatenating shorter regular expressions, starting from simple characters up to longer sub expressions. For example, you can define the patter "^hi.[it's me]" and it won't match the string "hi.it's me", but it will match "hi i" or "his" or even "hide". This is because the following characters have a meta meaning while not appearing escaped (prefixed by a "\"): You can make any of those special chars matching itself by escaping it, like "\?" for '?' or "\\" for '\'. Furthermore, you can create more complex expressions by composing REs using parenthesization. The bigger RE can be specified by several atoms like that: "me and (him|she)" and "((((this people:.* |that guys) are)|(noone is)) fried of mine)".

Text comparisons using REs are made easy by the regex library. See Summary.

Summary:

Examples:
1) Reimplementing egrep's basic behaviour. Obtained text from standard input, prints out those lines matching the regular expression got from command line. It can be useful to test REs too. Follows the source file:
/*
 *  qegrep.c
 *
 *  compares its standard input against the regular
 *  expression given (on command line), and prints
 *  out those lines matching that RE.
 *
 *
 *  Created by Mij <mij@bitchx.it> on Mon Dec 29 2003.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 */

 /* max error message length */
#define MAX_ERR_LENGTH 80
 /* max length of a line of text from stdin */
#define MAX_TXT_LENGTH 600

#include <stdio.h>
 /* for --ansi (see off_t in regex.h) */
#include <sys/types.h>
 /* for index(): */
#include <string.h>
#include <regex.h>


int main(int argc, char *argv[]) {
     /* will contain the regular expression */
    regex_t myre;
    int err;
    char err_msg[MAX_ERR_LENGTH];
    char text[MAX_TXT_LENGTH];
    
     /* safe check on cmd line args */
    if ( argc < 2 || argc > 2 ) {
        printf("Usage:\n\tqegrep 'RE' < file\n\tOR\n\techo \"string\" | qegrep 'RE'\n");
        return 1;
    }
    
     /* compiles the RE. If this step fails, reveals what's wrong with the RE */
    if ( (err = regcomp(&myre, argv[1], REG_EXTENDED)) != 0 ) {
        regerror(err, &myre, err_msg, MAX_ERR_LENGTH);
        printf("Error analyzing regular expression '%s': %s.\n", argv[1], err_msg);
        return 1;
    }
    
     /* "executes" the RE against the text taken from stdin */
    while ( fgets(text, MAX_TXT_LENGTH, stdin) != NULL ) {
         /* we rely on the fact that text contains newline chars */
        *(index(text, '\n')) = '\0';
        if ( (err = regexec(&myre, text, 0, NULL, 0)) == 0 ) puts(text);
        else if ( err != REG_NOMATCH ) {
             /* this is when errors have been encountered */
            regerror(err, &myre, err_msg, MAX_ERR_LENGTH);
            return 2;
        }
    } 

     /* meaningless here. Useful in many other situations. */
    regfree(&myre);
    
    return 0;
}

You can download the original ascii source file with this link: qegrep.c.
Compile with: gcc --ansi --pedantic -Wall -o qegrep qegrep.c
Run with: ./qegrep 'Newstyle Regular Expression'< textfile2scan or echo "string2scan" | ./qegrep 'Newstyle Regular Expression'


Parsing the command line


Notes:
This hasn't to be done manually but through the getopt() and getopt_long() facilities. Both them process the command line in form of (option, argument) pairs.
The getopt() function is the simplest one. It parses short options (i.e. like "-b -a -c -x option" or equivalently "-bcax option"). The getopt_long() function parses long options (i.e. like "--big-option --anotherone --check --extra=option", case sensitive!). Getopt_long also supports short options, and short-long options aliasing too: it is a actually super-set of getopt, a more difficult one.
The concept behind the getopt* functions is easy. They are both buffered functions (so they're not thread safe). They are given the array of command line parameters (argc and argv). They walk the array looking for any of the recognized options (a list specified by the programmer). When one is encountered, they return a reference to it, and possibly another one to its argument. The way they offer parsing is reactive: the programmer should specify the operations to be done after each call returned, wrt the option encountered.
For getopt(), the list of known options is a simple string like "abx:c". Every single character in the string is a known option. A character followed by a colon requires an argument. The order isn't regarded, but recommended in case of many options. Every time it's called, getopt() returns the next option in argv if it's recognized, "?" if it's not recognized, or "-1" if no more options have been found (exhaustion). Several global variables provided by an header file, the opt* vars, are set for carrying more info about the option. optopt points out the index of the option in *argv, and optarg points to the string which is argument of the current option, if any (unspecified otherwise).
For getopt_long(), the list of recognized options is still the option string as formerly, plus a support array, whose elements are each a structure describing an option: (name, has_argument, short_name_or_val). In the latter, name and has_argument are intuitive; short_name_or_val can be set to a recognized short option (an short-long aliasing will then occur), or to an arbitrary value to which set a memory location (see summary and examples below for details). getopt_long() return value is like getopt(), but 0 is returned when a long option is recognized.
Some automatic debugging is provided by these functions. They autonomously warn the user about missing arguments and unrecognized options. This default can be set off by setting to 0 the opterr global variable. In this case the return value is used to inspect what error have been found, if any: "?" for unknown option, ":" for missing argument.

Summary:
Examples:
1) A simple program that parses the command line option the classic way. Recognizes and handles both argument-less and -ful options, and is sensible to option repeated. Try executing without options, with repeated options (e.g. "-a -b -a") and with/without arguments for "-x".
/*
 *  getopt-short.c
 *  
 *  Parsing short-options command lines with getopt.
 *
 *
 *  Created by Mij <mij@bitchx.it> on 07/08/05.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 *
 */


#include <stdio.h>
#include <unistd.h>

#define OPT_NUM     4       /* a, b, c and x (h is not relevant here) */


int main(int argc, char *argv[]) {
    int want_opt[OPT_NUM];     /* want option? */
    char ch;                   /* service variables */
    int i;
    char *my_argument;
    
    
    /* init want_opt array */
    for (i = 0; i < OPT_NUM; i++)
       want_opt[i] = 0;

    /* optstring: a, b, c, h; and x taking an argument */
    while ((ch = getopt(argc, argv, "abchx:")) != -1) {     /* getopt() iterates over argv[] */
        switch (ch) {       /* what getopt() returned */
            case 'a':       /* a has been recognized (possibly for the second or more time) */
                want_opt[0] = want_opt[0] + 1;     /* remember about a */
                break;
            case 'b':       /* b */
                want_opt[1]++;
                break;
            case 'c':
                want_opt[2]++;
                break;
            case 'x':
                want_opt[3]++;
                my_argument = optarg;   /* preserve the pointer to x' argument */
                break;
            case 'h':   /* want help */
            default:
                /* no options recognized: print options summary */
                printf("Usage:\n%s [-a] [-b] [-c] [-h] [-x]\n", argv[0]);
                
                /* typically here: 
                exit(EXIT_FAILURE);
                */
        }
    }
    
    /* print out results */
    printf("You requested:\n");
    if (want_opt[0]) printf("a [%d]\n", want_opt[0]);
    if (want_opt[1]) printf("b [%d]\n", want_opt[1]);
    if (want_opt[2]) printf("c [%d]\n", want_opt[2]);
    if (want_opt[3]) printf("x [%d]: %s", want_opt[3], my_argument);  /* but only the last one rests */
 
    printf("\n");
    return 0;
}

You can download the original ascii source file with this link:
getopt-short.c.
Compile with: gcc --ansi --pedantic -Wall -o getopt-short getopt-short.c , or via the makefile in the package.
Run with: ./getopt-short -a -r -b -x -a -x foo -x

2) Parsing long options. This exemplifies the long-short option aliasing, and how to handle long options without a short counterpart.
/*
 *  getopt-long.c
 *  
 *  Parsing long-option command lines with getopt.
 *
 *
 *  Created by Mij <mij@bitchx.it> on 11/08/05.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 *
 */


#include <stdio.h>
/* for getopt_long() */
#include <getopt.h>


int main(int argc, char *argv[]) {
    char ch;                   /* service variables */
    int long_opt_index = 0;
    int longval;
    char *my_argument;
    struct option long_options[] = {        /* long options array. Items are all caSe SensiTivE! */
        { "add", 0, NULL, 'a'   },      /* --add or -a  */
        { "back", 0, NULL, 'b'  },      /* --back or -b */
        { "check", 0, &longval, 'c' },  /* return 'c', or return 0 and set longval to 'c' if "check" is parsed */
        { "extra", 1, &longval, 'x' },
        { 0,    0,    0,    0   }       /* terminating -0 item */
    };
    
    
    while ((ch = getopt_long(argc, argv, "abchx:", long_options, &long_opt_index)) != -1) {
       switch (ch) {
           case 'a':   /* long_opt_index does not make sense for these */
               /* 'a' and '--add' are confused (aliased) */
               printf("Option a, or --add.\n");
               break;
           case 'b':
               /* 'b' and '--back' are confused (aliased) */
               printf("Option b, or --back.\n");
               break;
           case 'c':
               /* 'c' and '--check' are distinguished, but handled the same way */
               printf("Option c, not --check.\n");
               break;
           case 'x':
               my_argument = optarg;
               printf("Option x, not --extra. Argument %s.\n", my_argument);
               break;
           case 0:     /* this is returned for long options with option[i].flag set (not NULL). */
                       /* the flag itself will point out the option recognized, and long_opt_index is now relevant */
               switch (longval) {
                   case 'c':
                       /* '--check' is managed here */
                       printf("Option --check, not -c (Array index: %d).\n", long_opt_index);
                       break;
                   case 'x':
                       /* '--extra' is managed here */
                       my_argument = optarg;
                       printf("Option --extra, not -x (Array index: %d). Argument: %s.\n", long_opt_index, my_argument);
                       break;
                   /* there's no default here */
               }
               break;
           case 'h':   /* mind that h is not described in the long option list */
               printf("Usage: getopt-long [-a or --add] [-b or --back] [-c or --check] [-x or --extra]\n");
               break;
           default:
               printf("You, lamah!\n");
       }
    }
    
    return 0;
}

You can download the original ascii source file with this link: getopt-long.c.
Compile with: gcc --ansi --pedantic -Wall -o getopt-long getopt-long.c , or via the makefile in the package.
Run with: ./getopt-long -a --foobar --back -x foo -b --check.

Tasks, fork(), wait() and waitpid()


Notes:
A task is an independent flow of instructions associated with a memory space and a private context. You can clone a task into another one which will consequently run concurrently and, once again, independently to it parent. The terms "parent", "child", "grandfather" etc. are common for describing the hierarchical relationship occurring between processes.
Immediately after the fork, the parent and the child are identical for both the code, the data and the context. They can modify everything in their environment independently because their contexts are separate. Since the code segment is identical, they will also run the same instructions just after the fork. Looking at the return value of the forking function is the only way to distinguish who's who. The parent is returned the Process ID of the child, whereas the child always gets the value "0".
The way to make this whole mechanism useful is actually to place a branch just after the fork and decide what to do depending on who is the parent and who is the child. The most common example to describe when tasks come useful is a server accepting connections. You can run a process that listens for incoming connections, and forks to a new child every time a new one occurs, delegating it to serve the client. This design is cleaner than creating a monolithic process which does everything itself.
POSIX defines pid_t fork(void) as function to fork a process. The fork() primitive can fail, for example, when the total number of concurrent processes allowed by the OS has been over-gone, or if some resource got exhausted. In this case no children are produced.
An important point to get is that nothing is said about which between the parent or the child executes first right after fork() returns. Well written code requires this is taken into account. If you postulate something about that, you're writing unreliable code.
Being processes, children can terminate and return exit values. The wait() function lets the parent fetch this value. It blocks the calling process until the first child terminates; then, it returns the pid of the child and stores its exit status. When a child terminates, the OS signals its parent with a SIGCHLD. When the parent produced several children and one particular is expected to terminate, the waitpid() function is to be used. Waitpid can also be instructed not to be blocking, thereby it is used frequently in place of wait() too. The SIGCHLD signal can also be bound to a "purging" wait() function for skipping zombies accumulation.
If a process terminates before any of its children, the process with PID 1 (init(8)) receives the paternity of them.

Summary:

Examples:
1) Practicing with paternities, pids, exit statuses. The process forks to a child, then waits for someone to terminate. The child forks into another child, and wait(pid) for it to terminate. This latter child forks into another child, doesn't expect for anyone and terminates.
/*
 *  procsmess.c
 *
 *  A completely meaningless example for tasks.
 *  The parent process forks, then wait() for output
 *  the exit status of who exited. The child forks
 *  and does the same with waitpid(). The grandchild
 *  finally forks and suddendly terminate.
 *
 *
 *  Created by Mij <mij@bitchx.it> on Wed Dec 31 2003.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 */

 /* for printf() and perror() */
#include <stdio.h>
 /* for fork() */
#include <sys/types.h>
#include <unistd.h>
 /* for wait*() */
#include <sys/wait.h>

int main() {
    pid_t mypid, childpid;
    int status;
    
     /* what's our pid? */
    mypid = getpid();
    printf("Hi. I'm the parent process. My pid is %d.\n", mypid);
    
     /* create the child */
    childpid = fork();
    if ( childpid == -1 ) {
        perror("Cannot proceed. fork() error");
        return 1;
    }
    
    
    if (childpid  == 0) {
         /* then we're the child process "Child 1" */
        printf("Child 1: I inherited my parent's pid as %d.\n", mypid);
        
         /* get our pid: notice that this doesn't touch the value of parent's "mypid" value */
        mypid = getpid();
        printf("Child 1: getppid() tells my parent is %d. My own pid instead is %d.\n", getppid(), mypid);
        
        
         /* forks another child */
        childpid = fork();
        if ( childpid == -1 ) {
            perror("Cannot proceed. fork() error");
            return 1;
        }
        
        if (childpid == 0) {
             /* this is the child of the first child, thus "Child 2" */
            printf("Child 2: I hinerited my parent's PID as %d.\n", mypid);
            
            mypid = getpid();
            printf("Child 2: getppid() tells my parent is %d. My own pid instead is %d.\n", getppid(), mypid);
            
            childpid = fork();
            if ( childpid == -1 ) {
                perror("Cannot proceed. fork() error");
                return 1;
            }
            
            if (childpid == 0) {
                 /* "Child 3" sleeps 30 seconds then terminates 12, hopefully before its parent "Child 2" */
                printf("Child 3: I hinerited my parent's PID as %d.\n", mypid);
                
                mypid = getpid();
                printf("Child 3: getppid() tells my parent is %d. My own pid instead is %d.\n", getppid(), mypid);
                
                sleep(30);
                return 12;
            } else   /* the parent "Child 2" suddendly returns 15 */  return 15;
        } else {
             /* this is still "Child 1", which waits for its child to exit */
            while ( waitpid(childpid, &status, WNOHANG) == 0 ) sleep(1);
            
            if ( WIFEXITED(status) ) printf("Child1: Child 2 exited with exit status %d.\n", WEXITSTATUS(status));
            else printf("Child 1: child has not terminated correctly.\n");
        }
    } else {
         /* then we're the parent process, "Parent" */
        printf("Parent: fork() went ok. My child's PID is %d\n", childpid);
         
         /* wait for the child to terminate and report about that */
        wait(&status);
        
        if ( WIFEXITED(status) ) printf("Parent: child has exited with status %d.\n", WEXITSTATUS(status));
        else printf("Parent: child has not terminated normally.\n");
    }
    
    return 0;
}

You can download the original ascii source file with this link:
procsmess.c.
Compile with: gcc --ansi --pedantic -Wall -o procsmess procsmess.c
Run with: ./procsmess


2) Handling lots of children. The parent loops forking. Each child does nothing and suddenly terminates. The parent cycles on waitpid to keep the exit statuses queue the shortest it can. Just put a "sleep(1);" into children to see a memory exhaustion or MAXPROCS reached. A desktop user will never see such an occurrence besides bugs, while servers can occasionally run into problems on this topic.
/*
 *  forkvswaitpid.c
 *  
 *  The parent loops forking and waiting.
 *  Notice the behaviour of both the post-fork()
 *  and post-waitpid() messages.
 *
 *
 *  Created by Mij <mij@bitchx.it> on Wed Dec 31 2003.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 */

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid;
    int status;
    
    printf("Hi. Your OS would get a bit busy right now. Please kill pressing ctrl+C\n");
    
    while (1) {
        pid = fork();
        
        if ( pid == -1 ) {
            perror("Error on fork()");
            return 1;
        }
        
        if (pid == 0) {
             /* we're the child */
            printf("One more child born.\n");
            return 0;
        } else
             /* we're the parent and we want to purge the queue of childs exited */
            while ( waitpid(-1, &status, WNOHANG) > 0 ) printf("One more child dead.\n");
    }
    
    return 0;
}

You can download the original ascii source file with this link: forkvswaitpid.c.
Compile with: gcc --ansi --pedantic -Wall -o forkvswaitpid forkvswaitpid.c
Run with: ./forkvswaitpid

Threads


Notes:
Threads are frequently reported as "alternatives to tasks". Since threads allow to satisfy a wider set of requirements than tasks, it's not fair to talk about them in these terms.
A thread is an independent stream of instructions running inside the scope of a process. A task can create several threads which will run concurrently. Threads live in the same context of their caller. Since their creation does not require the whole process context to be replicated in memory (as in fork()), they are way faster than tasks. The same questioning about context also plays for the lower scheduling overhead.
Since threads aren't independent of each other, they are also more difficult to use.
From the point of view of the developer, a thread is a function. The caller may thread the function to make it executing concurrently with the main stream of instructions. The function can access the whole context of the process it's running inside, e.g. global vars, open files and other functions.
Each instance has its own stack record, then an autonomous local scope. Multiple concurrent instances of a function will not share local variables then.
The real deal with threads is controlling overlaps and inconsistencies. Designing threaded applications is difficult. You must take care of your own code, but you must also take into account others' code. Libcalls you use must be thread-safe as well as *your* functions. In order to write thread-safe code, you must design thread-safe algorithms and involve thread-safe functions. Whether a library is thread-safe or not is normally reported explicitly on its man pages or in its source code.
pthreads are the standard thread API proposed by POSIX, and implemented by most of the POSIX-compliance OSes.
pthreads define a set of functions that let the programmer handle threads in a simple manner. They're partitioned into four main families depending on their goal: thread, attribute objects, Mut(ual)Ex(clusion) and condition variable routines. This page will just cover the first two families, the most commonly used. If you need to do something from the other ones, then you don't just need to quickly carry out a threaded program, and you might spend the time to carefully read the actual manpages.

Summary
Examples:
The following examples are from "Using POSIX Threads: Programming with Pthreads" by Brad nichols, Dick Buttlar, Jackie Farrell O'Reilly & Associates, Inc. I find they're quite complete, so I'm not going to spend time to write other ones. Unfortunately they're not documented. I added a short description of their behaviour on the top of their source code, and therein embedded some comment. Maybe in the future i'll write something more complete and clear (and better written) than them.

1) This shows out how to create and "join" threads. "Joining" for threads is analogue to "waiting" for tasks.
/********************************************************
 * An example source module to accompany...
 *
 * "Using POSIX Threads: Programming with Pthreads"
 *     by Brad nichols, Dick Buttlar, Jackie Farrell
 *     O'Reilly & Associates, Inc.
 *
 ********************************************************
 * simple_threads.c
 *
 * Simple multi-threaded example.
 * Creates two threads. While doing different things, they
 * both access and modify variables with global scope.
 * Those vars have been tought to be modified this way, so
 * this is *not* an example of a thread side effect. If each
 * thread'd been accessing the same variable, they could create
 * such kind of problems.
 */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>

void do_one_thing(int *);           /* first function to thread */
void do_another_thing(int *);       /* second function to thread */
void do_wrap_up(int, int);          /* after joining threads... */

int r1 = 0, r2 = 0;

extern int
main(void)
{
   /* ids for the first and the second thread */
  pthread_t thread1, thread2;
 
   /* creating the first thread. retval != 0 means troubles */
  if (pthread_create(&thread1, 
         NULL,
         (void *) do_one_thing,
         (void *) &r1) != 0)
    perror("pthread_create"), exit(1); 
  
   /* creating the first thread. retval != 0 means troubles.
    * its argument is passed with a void * casting as requested
    * by pthread_create. The actual function expects an int. */
  if (pthread_create(&thread2, 
         NULL, 
         (void *) do_another_thing,
         (void *) &r2) != 0)
    perror("pthread_create"), exit(1); 
  
   /* waiting for the first thread to terminate.
    * Thread's return(/exit) value gets discarded. */
  if (pthread_join(thread1, NULL) != 0)
    perror("pthread_join"),exit(1);
 
   /* waiting for the second thread */
  if (pthread_join(thread2, NULL) != 0)
    perror("pthread_join"),exit(1);

  do_wrap_up(r1, r2);

  return 0; 
}

void do_one_thing(int *pnum_times)
{
  int i, j, x;
  
  for (i = 0;  i < 4; i++) {
    printf("doing one thing\n"); 
    for (j = 0; j < 10000; j++) x = x + i;
    (*pnum_times)++;
  }

}

void do_another_thing(int *pnum_times)
{
  int i, j, x;
  
  for (i = 0;  i < 4; i++) {
    printf("doing another \n"); 
    for (j = 0; j < 10000; j++) x = x + i;
    (*pnum_times)++;
  }

}

void do_wrap_up(int one_times, int another_times)
{
  int total;

  total = one_times + another_times;
  printf("All done, one thing %d, another %d for a total of %d\n",
    one_times, another_times, total);
}

You can download the original ascii source file with this link:
simple_threads.c.
Compile with: gcc --pedantic -Wall -o simple_threads simple_threads.c
Run with: ./simple_threads


2) A precious example on Mutual Exclusion.
/********************************************************
 * An example source module to accompany...
 *
 * "Using POSIX Threads: Programming with Pthreads"
 *     by Brad nichols, Dick Buttlar, Jackie Farrell
 *     O'Reilly & Associates, Inc.
 *
 ********************************************************
 * simple_mutex.c
 *
 * Simple multi-threaded example with a mutex lock.
 * Does the same as the example above (see the link below)
 * but with mutual exclusion. Any time a thread starts, it
 * request the thread lock. Just one thread is executing
 * anytime. The others must wait it to unlock before proceeding.
 * quickly comment out by Mij <mij@bitchx.it> for
 * http://mij.oltrelinux.com/devel/unixprg/
 *
 * (also modified a bit on the code itself for clarity and
 * expressiveness purposes)
 */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>

void do_one_thing(int *);       /* first thread */
void do_another_thing(int *);       /* second thread */
void do_wrap_up(int, int);

int r1 = 0, r2 = 0, r3 = 0;
pthread_mutex_t r3_mutex=PTHREAD_MUTEX_INITIALIZER; /* for mutex locking */

extern int
main(int argc, char **argv)
{
   /* thread ids */
  pthread_t thread1, thread2;

  if (argc > 1) 
    r3 = atoi(argv[1]);

   /* creating the first thread */
  if (pthread_create(&thread1, 
         NULL,
         (void *) do_one_thing,
         (void *) &r1) != 0)
    perror("pthread_create"),exit(1); 

   /* creating the second thread */
  if (pthread_create(&thread2, 
         NULL, 
         (void *) do_another_thing,
         (void *) &r2) != 0)
    perror("pthread_create"),exit(1); 
  
   /* expecting the first thread to terminate */
  if (pthread_join(thread1, NULL) != 0)
    perror("pthread_join"), exit(1);
  
   /* expecting the second thread to terminate */
  if (pthread_join(thread2, NULL) != 0)
    perror("pthread_join"), exit(1);

  do_wrap_up(r1, r2);

  return 0; 
}

void do_one_thing(int *pnum_times)
{
  int i, j, x;
  pthread_t ti;

  ti = pthread_self();      /* which's our id? */
  pthread_mutex_lock(&r3_mutex);
   /* this is the segment containing sensitive operations.
    * So we need to keep it alone from concurrency for safeness. */
  if(r3 > 0) {
    x = r3;
    r3--;
  } else {
    x = 1;
  }
   /* sensitive code end */
  pthread_mutex_unlock(&r3_mutex); 

  for (i = 0;  i < 4; i++) {
    printf("doing one thing\n"); 
      for (j = 0; j < 10000; j++) x = x + i;
      printf("thread %d: got x = %d\n", (int)ti, x);
    (*pnum_times)++;
  }

}

void do_another_thing(int *pnum_times)
{
  int i, j, x;
  pthread_t ti;
    
  ti = pthread_self();
  pthread_mutex_lock(&r3_mutex);
  if(r3 > 0) {
        x = r3;
        r3--;
  } else {
        x = 1;
  }
  pthread_mutex_unlock(&r3_mutex);

  for (i = 0;  i < 4; i++) {
    printf("doing another \n"); 
    for (j = 0; j < 10000; j++) x = x + i;
    printf("thread %d: got x = %d\n", (int)ti, x);
    (*pnum_times)++;
  }

}

void do_wrap_up(int one_times, int another_times)
{
  int total;

  total = one_times + another_times;
  printf("All done, one thing %d, another %d for a total of %d\n",
    one_times, another_times, total);
}

You can download the original ascii source file with this link: simple_mutex.c.
Compile with: gcc --pedantic -Wall -o simple_threads simple_mutex.c.
Run with: ./simple_mutex

IPC: signals


Notes:
A signal is a very primitive kind of message. Process A can send process B a signal. If B associated an handler to the given signal, that code will be executed when the signal is received, interrupting the normal execution.
Originally, signals were simply unary values (received or not, like a beep): when a process received the signal, it always reacted the same manner (historically, terminating, that also explains the current name of the function you'll see below for sending signals). Recently, signals have been "type-fied" (think about beeps of different frequencies): when a process receives a signal, it reacts differently depending on the signal's type. This type is an integer value. Some values have been conventionally standardized and associated with symbolic names: (15, TERM) and (20, CHLD) are popular examples. The full list is defined in signal.h.
Processes send signals with the kill() function. A process may associate an handler function to a specific signal type with the signal() function.
Signal dispatching is controlled by the operating system. A process A can signal another process only if they belong to the same user. Processes run by a superuser can signal every process. Signals are often sent by the OS itself, e.g. to kill a process when its execution caused problems like memory segment violation. For some of these signals, the OS inhibits custom handlers: SIGSTOP and SIGKILL will always make the process respectively stop and die.
Two standard handlers have been provided with the standard C library: SIG_DFL causing process termination, and SIG_IGN causing the signal to get ignored. When an handler fires for a signal, it won't be interrupted by other handlers if more signals arrive.
As last note: signals are not queued (somehow, "best effort"). In order to notify signals, the OS holds a bitmask for every process. When the process receives the signal n, the nth bit in this bitmask is set. When the handler function terminates, it's reset to 0. Thus, if the process is not scheduled for execution (some of its user-space code) before other signals of the same type arrive, only the last will be notified by the process. The others are lost.

Summary:
Examples:
1) Handling signals coming from the operating system. This example implements a solution to the problem of purging the queue of exit statuses of dead children. Whenever a child changes its status, the parent is signaled (by the OS) with "SIGCHLD". A SIGCHLD handler can be associated with this event. There are 2 important things to note for this process:
  1. the signal handler may catch all the dead children, or not. The random sequence delaying forks contributes to signals overlapping phenomenon.
  2. the raise of the signal handler (child_handler()) turn the process back in a "running" state. In this case, it breaks the sleep() functions before the exhaust their module.
/*
 *  sig_purgechilds.c
 *  
 *  The parent process pulls a child exit status whenever the OS notifies
 *  a child status change.
 *
 *  Created by Mij <mij@bitchx.it> on 04/01/05.
 *  Original source file available at http://mij.oltrelinux.com/devel/unixprg/
 *
 */

/* for printf() and fgetc() */
#include <stdio.h>
/* for fork() */
#include <sys/types.h>
#include <unistd.h>
/* for srandom() and random() */
#include <stdlib.h>
/* for time() [seeding srandom()] */
#include <time.h>
/* for waitpid() */
#include <sys/wait.h>
/* for signal(), kill() and raise() */
#include <signal.h>

/* how many childs to raise */
#define NUM_PROCS   5


/* handler prototype for SIGCHLD */
void child_handler(int);

int main(int argc, char *argv[])
{
    int i, exit_status;
    
    
    /* execute child_handler() when receiving a signal of type SIGCHLD */
    signal(SIGCHLD, &child_handler);

    /* initialize the random num generator */
    srandom(time(NULL));
    
    
    printf("Try to issue a \'ps\' while the process is running...\n");
    
    
    /* produce NUM_PROCS childs */
    for (i = 0; i < NUM_PROCS; i++) {
        if (! fork()) {
            /* child */
            
            /* choosing a random exit status between 0 and 99 */
            exit_status = (int)(random() % 100);
            printf(" -> New child %d, will exit with %d.\n", (int)getpid(), exit_status);
            
            /* try to skip signals overlapping */
            sleep((unsigned int)(random() % 3));
            
            /* choosing a value to exit between 0 and 99 */
            exit(exit_status);
        } 
        
        /* father */
        sleep((unsigned int)(random() % 2));
    }

    /* checkpoint */
    printf("parent: done with fork()ing.\n");

    /* why this is not equivalent to sleep(20) here? */
    for (i = 0; i < 10; i++) {
        sleep(1);
    }
    /* all the child processes should be done now */
    printf("I did not purge all the childs. Timeout; exiting.\n");
    
    /* terminate myself => exit */
    kill(getpid(), 15);
    
    /* this won't be actually executed */
    return 0;
}


/* handler definition for SIGCHLD */
void child_handler(int sig_type)
{
    int child_status;
    pid_t child;
    static int call_num = 0;

    /* getting the child's exit status */
    child = waitpid(0, &child_status, 0);
    
    printf("<-  Child %d exited with status %d.\n", child, WEXITSTATUS(child_status)); 
    
    /* did we get all the childs? */
    if (++call_num >= NUM_PROCS) {
        printf("I got all the childs this time. Going to exit.\n");
        exit (0);
    }
    
    return;
}

You can download the original ascii source file with this link: sig_purgechilds.c.
Compile with: gcc -o sig_purgechilds -Wall --ansi sig_purgechilds.c .
Run with: ./sig_purgechilds.c .


IPC: pipes


Notes:
A pipe is an uni-directional mean to send data. On UNIX systems, it's implemented with a couple of file descriptors. What is written on the first one can be read from the second one, with a FIFO order.
Pipes are one of the easiest and fastest way for implementing IPC between two processes. Commonly, a process creates two pipes X and Y and forks to a child. The child will inherit these data. The parent will message the child on X_w (the write descriptor of the X pipe), and the child will receive on X_r. In analogy, the child will write to the parent on Y_w; the parent can read from Y_r. Using the same pipe for bi-directional communication can bring high-quality messes, so the fair way to implement bi-directional communication is just to use two pipes (P1 to P2, and P2 to P1).
Thereby, it is clear that n*(n-1) pipes are needed for a n processes to intercommunicate together.
Atomicity of pipe operations is guaranteed by the OS if the length of the message is shorter than a specific value (carried by the PIPE_BUF macro), but if this information is relevant for you, pipes are probably not a good programming choice for your scenario.
When one of the two pipe ends is closed, the pipe becomes widowed (or broken). Writing to a widowed pipe is not permitted by the OS. On such a trial, the process is signalled with a SIGPIPE. Reading from widowed pipes always returns 0 bytes. This is often used to notify one end process the communication is finished.

Summary:
Examples:
1) a set of processes messaging together. Every process gets its own pipe (couple of file descriptors). When process i wants to message process j, it writes onto j's pipe write end. Every process will get its messages reading from the read end of its own pipe. This is a de-genere example with processes only reading the first 2 messages they got. The full solution can be implemented with the help of the select() function.
/*
 *  pipes.c
 *  
 *  A set of processes randomly messaging each the other, with pipes.
 *
 *
 *  Created by Mij <mij@bitchx.it> on 05/01/05.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 *
 */

/* ... */
#include <stdio.h>
/* for read() and write() */
#include <sys/types.h>
#include <sys/uio.h>
/* for strlen and others */
#include <string.h>
/* for pipe() */
#include <unistd.h>
/* for [s]random() */
#include <stdlib.h>
/* for time() [seeding srandom()] */
#include <time.h>


#define PROCS_NUM               15          /* 1 < number of processes involved <= 255 */
#define MAX_PAYLOAD_LENGTH      50          /* message length */
#define DEAD_PROC               -1          /* a value to mark a dead process' file descriptors with */


        /*      ***                     DATA TYPES                  ***     */
/* a process address */
typedef char proc_addr;

/* a message */
struct message_s {
    proc_addr src_id;
    short int length;
    char *payload;
};


        /*      ***                     FUNCTION PROTOTYPES         ***     */
/* send message to process with id dest */
int send_proc_message(proc_addr dest, char *message);
/* receive a message in the process' queue of received ones */
int receive_proc_message(struct message_s *msg);
/* mark process file descriptors closed */
void mark_proc_closed(proc_addr process);


        /*              ***             GLOBAL VARS                 ***     */
/* they are OK to be global here. */
proc_addr my_address;                   /* stores the id of the process */
int proc_pipes[PROCS_NUM][2];           /* stores the pipes of every process involved */


int main(int argc, char *argv[])
{
    pid_t child_pid;
    pid_t my_children[PROCS_NUM];               /* PIDs of the children */
    int i, ret;
    char msg_text[MAX_PAYLOAD_LENGTH];       /* payload of the message to send */
    proc_addr msg_recipient;                    
    struct message_s msg;
    
    
    
    /* create a pipe for me (the parent) */
    pipe(proc_pipes[0]);

    /* initializing proc_pipes struct */
    for (i = 1; i < PROCS_NUM; i++) {
        /* creating one pipe for every (future) process */
        ret = pipe(proc_pipes[i]);
        if (ret) {
            perror("Error creating pipe");
            abort();
        }        
    }
        
    
    /* fork [1..NUM_PROCS] children. 0 is me. */
    for (i = 1; i < PROCS_NUM; i++) {
        /* setting the child address */
        my_address = my_address + 1;
        
        child_pid = fork();
        if (! child_pid) {
            /* child */
            sleep(1);

            /* closing other process' pipes read ends */
            for (i = 0; i < PROCS_NUM; i++) {
                if (i != my_address)
                    close(proc_pipes[i][0]);
            }
            
            
            /* init random num generator */
            srandom(time(NULL));

            /* my_address is now my address, and will hereby become a "constant" */
            /* producing some message for the other processes */
            while (random() % (2*PROCS_NUM)) {
                /* interleaving... */
                sleep((unsigned int)(random() % 2));
                
                /* choosing a random recipient (including me) */
                msg_recipient = (proc_addr)(random() % PROCS_NUM);
                
                /* preparing and sending the message */
                sprintf(msg_text, "hello from process %u.", (int)my_address);
                ret = send_proc_message(msg_recipient, msg_text);
                if (ret > 0) {
                    /* message has been correctly sent */
                    printf("    --> %d: sent message to %u\n", my_address, msg_recipient);
                } else {
                    /* the child we tried to message does no longer exist */
                    mark_proc_closed(msg_recipient);
                    printf("    --> %d: recipient %u is no longer available\n", my_address, msg_recipient);
                }
            }
            
            /* now, reading the first 2 messages we've been sent */
            for (i = 0; i < 2; i++) {
                ret = receive_proc_message(&msg);
                if (ret < 0) break;
                printf("<--     Process %d, received message from %u: \"%s\".\n", my_address, msg.src_id, msg.payload);
            };
            
            /* i'm exiting. making my pipe widowed */
            close(proc_pipes[my_address][0]);
            
            printf("# %d: i am exiting.\n", my_address);
            exit(0);
        }
        
        /* saving the child pid (for future killing) */
        my_children[my_address] = child_pid;

        /* parent. I don't need the read descriptor of the pipe */ 
        close(proc_pipes[my_address][0]);
        
        /* this is for making srandom() consistent */
        sleep(1);
    }
    
    /* expecting the user request to terminate... */
    printf("Please press ENTER when you like me to flush the children...\n");
    getchar();

    printf("Ok, terminating dandling processes...\n");
    /* stopping freezed children */
    for (i = 1; i < PROCS_NUM; i++) {
        kill(my_children[i], SIGTERM);
    }
    printf("Done. Exiting.\n");
    
    return 0;
}


int send_proc_message(proc_addr dest, char *message)
{
    int ret;
    char *msg = (char *)malloc(sizeof(message) + 2);
    
    
    /* the write should be atomic. Doing our best */
    msg[0] = (char)dest;
    memcpy((void *)&(msg[1]), (void *)message, strlen(message)+1);
    
    /* send message, including the "header" the trailing '\0' */
    ret = write(proc_pipes[dest][1], msg, strlen(msg)+2);
    free(msg);
    
    return ret;
}


int receive_proc_message(struct message_s *msg)
{
    char c = 'x';
    char temp_string[MAX_PAYLOAD_LENGTH];
    int ret, i = 0;

    
    /* first, getting the message sender */
    ret = read(proc_pipes[my_address][0], &c, 1);
    if (ret == 0) {
        return 0;
    }
    msg->src_id = (proc_addr)c;

    do {
        ret = read(proc_pipes[my_address][0], &c, 1);
        temp_string[i++] = c;
    } while ((ret > 0) && (c != '\0') && (i < MAX_PAYLOAD_LENGTH));

    
    
    if (c == '\0') {
        /* msg correctly received. Preparing message packet */
        
        msg->payload = (char *)malloc(strlen(temp_string) + 1);
        strncpy(msg->payload, temp_string, strlen(temp_string) + 1);
        
        return 0;
    }


    return -1;
}


void mark_proc_closed(proc_addr process)
{
    proc_pipes[process][0] = DEAD_PROC;
    proc_pipes[process][1] = DEAD_PROC;
}

You can download the original ascii source file with this link: pipes.c.
Compile with: gcc --ansi --pedantic -o pipes pipes.c
Run with: ./pipes

IPC: named pipes


Notes:
There isn't much to say about named pipes once you understood standard pipes. The former ones are just a simple extension to the latter. In order to create a common pipe you use the pipe() function, and get a reference to it in terms of file descriptors. This is the big limit of pipes: with file descriptors, they can only be shared between processes with parent-child relationship. Named pipes work much like common pipes, but they can be shared between independent processes.
You request a FIFO file to enter the filesystem with the mkfifo() function. This takes as argument the name you want the file to appear like. Every other process with opportune credentials could then handle this special file with the standard open(), close(), read() and write() file functions.
The first process who open the fifo is blocked until the other end is opened by someone. Of course, being named pipes actual pipes in first place, they can't be applied functions like lseek(). This is common to every stream file including pipes, FIFOs and sockets. As a difference, being named pipes actually outside of the inner, private scope of a process, they will survive the death of their creator: they are persistent. This means that you must explicitly handle the named pipe removal after you're done with it. unlink() is what you need for this.

Summary:
Examples:
1) a simple example. There's not much more to address about fifos.
That's what you do to try this:
  1. you create the named pipe from the command line: mkfifo /tmp/named_pipe
  2. you compile this program, and run it
  3. you write something on the pipe: echo "this is a message" > /tmp/named_pipe
  4. you try what happens when skipping the string terminator: echo -n "this is another message" > /tmp/named_pipe
  5. then try to load a terminator on the fifo: echo "a third message" > /tmp/named_pipe
  6. when you're happy with your test, close the program. Then remove the pipe: rm /tmp/named_pipe
/*
 *  nampipes.c
 *  
 *  simply opens a pre-created named pipe (a "fifo") and reads
 *  stuff from it as soon as there's something available.
 *
 *
 *  Created by Mij <mij@bitchx.it> on 02/02/05.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

#define MAX_LINE_LENGTH


int main(int argc, char *argv[]) {
    int pipe;
    char ch;
    

    /* we expect a named pipe has been created
     * in /tmp/named_pipe . The command
     *   $ mkfifo /tmp/named_pipe
     * is a friend to get to this point
     */
    pipe = open("/tmp/named_pipe", O_RDONLY);
    if (pipe < 0) {
        perror("Opening pipe");
        exit(1);
    }
        
    /* preparing to read from the pipe... */
    printf("Waiting data from the pipe... \n");

    /* reading one char a time from the pipe */
    while (1) {
        if (read(pipe, &ch, 1) < 0) {
            perror("Read the pipe");
            exit(2);
        }
        
        printf("%c", ch);
    }
    
    /* leaving the pipe */
    close(pipe);
    
    return 0;
}

You can download the original ascii source file with this link: nampipes.c.
Compile with: gcc --ansi --Wall -o nampipes nampipes.c
Read the instructions above, then run with: ./nampipes

IPC: BSD sockets


Notes:
Sockets are the representation that the operating system provides for network endpoints to processes. They originated in 4.2BSD and are today an essential feature of every UNIX system.
Sockets are given a type and a set of attributes that depend on it. These attributes include an address: the set of possible values this address is taken from is told domain. As domains are distinct for each type, sockets are typically distinguished just by the domain they are addressed in. The most commonly used domains are the UNIX domain, that uses filename-like addresses and is suitable only for in-host IPC, and the INET domain, that uses IP addresses and can be used for both in-host and inter-host IPC, but many more domains exist.
Sockets can be connected or not. Connectionful sockets require a setup phase before the actual communication occurs, and a tear down phase after. Connectionless ones don't, but require a slightly more complex semantic for sending and receiving every single message.
Connectionless sockets are point-to-anypoint and peer. This is the lifecycle of a non-connected socket:
  1. it is created (here the belonging domain is specified); -- socket()
  2. it's bound attributes; -- bind()
  3. it is used for sending or receiving single messages; -- sendto() and recvfrom()
  4. it is closed -- close()
Connectionful sockets are strictly point-to-point: once a connection is established, messages only travel from/to the two entities involved. Connection also makes these sockets master/slave or client/server (the one who initiate the connection is told slave or client). This is the lifecycle of a connected socket with a role of server:
  1. it is created (and assigned a domain); -- socket()
  2. it's bound attributes; -- bind()
  3. it's open into a network port (listening); -- listen()
  4. it accept connections; -- accept()
  5. data is read and written on it (it represent a stream once connected); -- write() and read()
  6. it is closed -- close()
The lifecycle of a client is similar, but features a connection request (connect()) in place of points {2,3,4}.
When connected, sockets appears much like a file: they can be read and written the same way that file descriptors are.
Sockets are blocking by default: functions are suspended until the requested job on the socket terminates. However, like regular file descriptors, sockets can be set non-blocking too, with fcntl().

Summary:
Examples:
N.B.: It is an habit (that I dislike) that examples about sockets include a sample client, a sample server, and mr. sample client contacts mr. sample server and they are happy and close the connection. These examples are not like that. Both connected and connectionless sockets are presented. Besides, "standalone" clients and servers are proposed: their functionality can be tested with standard tools like netcat.

1) an UDP server. A connectionless socket is opened on the local internet-protocol interface "127.0.0.1", port "12321", and a message is awaited. Once received, the message length and content are displayed, along with the IP address and port of the sender.
/*
 * udpserv.c
 *
 * listens on an UDP port, accept one message and displays its content and
 * who's the sender
 *
 *
 * Created by Mij <mij@bitchx.it> on 18/12/05.
 * Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 */

#include <stdio.h>
/* socket(), bind(), recvfrom() */
#include <sys/types.h>
#include <sys/socket.h>
/* sockaddr_in */
#include <netinet/in.h>
/* inet_addr() */
#include <arpa/inet.h>
/* memset() */
#include <string.h>
/* close() */
#include <unistd.h>
/* exit() */
#include <stdlib.h>

/* maximum size available for an incoming message payload */
#define MAX_MSGLEN      100

int main() {
    int sock, err;
    char messagebuf[MAX_MSGLEN+1];
    struct sockaddr_in saddr, fromaddr;
    int fromaddr_len = sizeof(fromaddr);


    /* create a INET-domain, disconnected (datagram) socket */
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock < 0) {
        perror("In socket()");
        exit(1);
    }

    /* bind the following attributes to the socket: */
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");     /* localhost address */
    saddr.sin_port = htons(61321);          /* use port 61321 (with correct network byte-order */
    memset(&saddr.sin_zero, 0, sizeof(saddr.sin_zero)); /* always zero-fill this field! */
    
    err = bind(sock, (struct sockaddr *)&saddr, sizeof(saddr));
    if (err) {
        perror("In bind()");
        exit(1);
    }
   
    /* receive a message in "messagebuf" at most MAX_MSGLEN bytes long (1 is
     * spared for the trailing '\0'; store sender info in "fromaddr" */
    err = recvfrom(sock, messagebuf, MAX_MSGLEN-1, 0, (struct sockaddr *)&fromaddr, &fromaddr_len);
    if (err <= 0) {     /* otherwise, "err" tells how many bytes have been written in "messagebuf" */
        perror("in recvfrom()");
        exit(1);
    }
    messagebuf[err] = '\0';        /* NULL-terminator */

    /* close the socket */
    close(sock);
    
    /* displaying message length and content */
    printf("Message:\n\t@bytes: %d\n\t@payload: %s\n", err, messagebuf);
    /* displaying sender info: */
    printf("Sender:\n\t@address: %s\n\t@port: %d\n", inet_ntoa(fromaddr.sin_addr), ntohs(fromaddr.sin_port));

    return 0;
}

You can download the original ascii source file with this link: udpserv.c.
Compile with: gcc -o udpserv udpserv.c
Run the server in a terminal:
$ ./udpserv
Then, open another terminal and feed something on UDP on 127.0.0.1 port 61321 via UDP, e.g. with netcat:
$ echo -n "Hello lame server." | nc -u 127.0.0.1 61321
Also try omitting the newline (here, take "-n" away), and sending large messages (eg, cat a whole file).
2) A UNIX domain client. It connects to a given server, sends a message to it, expects a newline-terminated response, then displays all this and exits.
/*
 * unixcli.c
 *
 * connects to an UNIX domain socket, sends a message to it, and disconnects.
 *
 *
 * Created by Mij <mij@bitchx.it> on 18/12/05.
 * Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 */

#include <stdio.h>
/* socket(), bind() */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
/* write(), close() */
#include <unistd.h>
/* strlen() */
#include <string.h>
/* exit() */
#include <stdlib.h>

/* maximum size available for an incoming message payload */
#define MAX_MSGLEN      100
/* path of the UNIX domain socket in filesystem */
#define SERVERSOCK_PATH     "/tmp/mytmpunixsock"

int main() {
    int sock, err, i = 0;
    char ch, messagebuf[MAX_MSGLEN];
    struct sockaddr_un servaddr;


    /* create a UNIX domain, connectionful socket */
    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("In socket()");
        exit(1);
    }

    /* connect the socket to the server socket described by "servaddr" */
    servaddr.sun_family = AF_UNIX;
    sprintf(servaddr.sun_path, SERVERSOCK_PATH);

    err = connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if (err) {
        perror("In connect()");
        exit(1);
    }

    /* write a message to the server */
    err = write(sock, "Hello server.\n", strlen("Hello server.\n"));
    if (err < 0) {
        perror("In write()");
        exit(1);
    }

    printf("Message sent:\n\t@length: %d bytes\n\t@content: %s\n", err, "Hello server.\n");

    /* receive the response from the server */
    do {
        err = read(sock, &ch, 1);       /* read one byte from the socket */
        if (err <= 0) {
            printf("Premature end-of-file (0) or read() error (<0)? %d\n", err);
            break;
        }
        messagebuf[i++] = ch;
    } while (ch != '\n');
    messagebuf[i] = '\0';
   
    /* close the socket */
    close(sock);
    
    printf("Response received:\n\t@length: %lu bytes\n\t@content: %s\n", strlen(messagebuf), messagebuf);

    return 0;
}
        

You can download the original ascii source file with this link: unixcli.c .
Compile with: gcc -o unixcli unixcli.c
Before running, establish a UNIX domain socket, e.g. with socat:
$ socat UNIX-LISTEN:/tmp/mytmpunixsock -
In another terminal, run the client with:
$ ./unixcli
You see the message incoming from the client to the server in the first terminal. The client expects a response now: type something (newline-terminated) and see what the client tells. Also try interrupting the connection prematurely by Ctrl-C 'ing the server. (Manually remove the socket created by socat after use).

IPC: POSIX Message queues


Notes:
Message queues are an handy way to get IPC when working with unrelated processes that run completely without synchronism. A message queue is a shared "box" where processes can drop and withdraw messages independently. Besides the content, each message is given a "priority". Message queues first appeared in System V. POSIX standardized this IPC mechanism with the 1003.1b ("realtime") standard in 1993, but the resulting standard is describing a slightly different behavior wrt the former historical implementation. This is about the POSIX interface.
Message queues objects are referenced by a unique POSIX object name in the system as usual. The opening function (mq_open()) is the only one to use that name, while an internal reference returned by it will be used to reference the queue for the remainder of the program.
Messages are sent to the queue with the mq_send() (blocking by default). They can be any kind of information, nothing is dictated on the structure of a message. On sending, the message is to be accompanied by a priority. This priority is used for delivering messages: every time a process request for a receive (invoking the mq_receive() function, also blocking by default), the oldest message with the highest priority will be given. This differs from the SysV API, in which the user explicitly request for a specific priority, causing this priority being frequently used as recipient address.
Several features of the message queue can be set on creation or, in part, on a later time with the mq_setattr() function. Between them, the maximum size of a message is worth particular attention: each process invoking a receive won't be serviced, and EMSGSIZE will be set in errno if the length of the buffer for the message is shorter than this maximum size.

Summary:
Examples:
1) Handling creation/opening of message queues, sending/receiving of messages and the essence of queue attributes. Try running several times the message producer before running the consumer. Try running the consumer more times than the producer. Try looping the producer until the queue fills. Try running the consumer after decreasing MAX_MSG_LEN under what's displayed by the queue attributes.
/*
 *  dropone.c
 *  
 *  drops a message into a #defined queue, creating it if user
 *  requested. The message is associated a priority still user
 *  defined
 *
 *
 *  Created by Mij <mij@bitchx.it> on 07/08/05.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 *
 */

#include <stdio.h>
/* mq_* functions */
#include <mqueue.h>
#include <sys/stat.h>
/* exit() */
#include <stdlib.h>
/* getopt() */
#include <unistd.h>
/* ctime() and time() */
#include <time.h>
/* strlen() */
#include <string.h>


/* name of the POSIX object referencing the queue */
#define MSGQOBJ_NAME    "/myqueue123"
/* max length of a message (just for this process) */
#define MAX_MSG_LEN     70


int main(int argc, char *argv[]) {
    mqd_t msgq_id;
    unsigned int msgprio = 0;
    pid_t my_pid = getpid();
    char msgcontent[MAX_MSG_LEN];
    int create_queue = 0;
    char ch;            /* for getopt() */
    time_t currtime;
    
    
    /* accepting "-q" for "create queue", requesting "-p prio" for message priority */
    while ((ch = getopt(argc, argv, "qi:")) != -1) {
        switch (ch) {
            case 'q':   /* create the queue */
                create_queue = 1;
                break;
            case 'p':   /* specify client id */
                msgprio = (unsigned int)strtol(optarg, (char **)NULL, 10);
                printf("I (%d) will use priority %d\n", my_pid, msgprio);
                break;
            default:
                printf("Usage: %s [-q] -p msg_prio\n", argv[0]);
                exit(1);
        }
    }
    
    /* forcing specification of "-i" argument */
    if (msgprio == 0) {
        printf("Usage: %s [-q] -p msg_prio\n", argv[0]);
        exit(1);
    }
    
    /* opening the queue        --  mq_open() */
    if (create_queue) {
        /* mq_open() for creating a new queue (using default attributes) */
        msgq_id = mq_open(MSGQOBJ_NAME, O_RDWR | O_CREAT | O_EXCL, S_IRWXU | S_IRWXG, NULL);
    } else {
        /* mq_open() for opening an existing queue */
        msgq_id = mq_open(MSGQOBJ_NAME, O_RDWR);
    }
    if (msgq_id == (mqd_t)-1) {
        perror("In mq_open()");
        exit(1);
    }

    /* producing the message */
    currtime = time(NULL);
    snprintf(msgcontent, MAX_MSG_LEN, "Hello from process %u (at %s).", my_pid, ctime(&currtime));
    
    /* sending the message      --  mq_send() */
    mq_send(msgq_id, msgcontent, strlen(msgcontent)+1, msgprio);
    
    /* closing the queue        -- mq_close() */
    mq_close(msgq_id);
    
        
    return 0;
}

/*
 *  takeone.c
 *  
 *  simply request a message from a queue, and displays queue
 *  attributes.
 *
 *
 *  Created by Mij <mij@bitchx.it> on 07/08/05.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 *
 */

#include <stdio.h>
/* mq_* functions */
#include <mqueue.h>
/* exit() */
#include <stdlib.h>
/* getopt() */
#include <unistd.h>
/* ctime() and time() */
#include <time.h>
/* strlen() */
#include <string.h>


/* name of the POSIX object referencing the queue */
#define MSGQOBJ_NAME    "/myqueue123"
/* max length of a message (just for this process) */
#define MAX_MSG_LEN     10000


int main(int argc, char *argv[]) {
    mqd_t msgq_id;
    char msgcontent[MAX_MSG_LEN];
    int msgsz;
    unsigned int sender;
    struct mq_attr msgq_attr;
    
    
    /* opening the queue        --  mq_open() */
    msgq_id = mq_open(MSGQOBJ_NAME, O_RDWR);
    if (msgq_id == (mqd_t)-1) {
        perror("In mq_open()");
        exit(1);
    }

    /* getting the attributes from the queue        --  mq_getattr() */
    mq_getattr(msgq_id, &msgq_attr);
    printf("Queue \"%s\":\n\t- stores at most %ld messages\n\t- large at most %ld bytes each\n\t- currently holds %ld messages\n", MSGQOBJ_NAME, msgq_attr.mq_maxmsg, msgq_attr.mq_msgsize, msgq_attr.mq_curmsgs);

    /* getting a message */
    msgsz = mq_receive(msgq_id, msgcontent, MAX_MSG_LEN, &sender);
    if (msgsz == -1) {
        perror("In mq_receive()");
        exit(1);
    }
    printf("Received message (%d bytes) from %d: %s\n", msgsz, sender, msgcontent);
    
    /* closing the queue    --  mq_close() */
    mq_close(msgq_id);
    
    
    return 0;
}

You can download the original ascii source files with these links: dropone.c and takeone.c.
Compile with:
gcc --pedantic -Wall -o dropone dropone.c
gcc --pedantic -Wall -o takeone takeone.c

(some systems wrap these functions into a posix realtime library: add -lrt for them -- e.g. Linux does)
Run as follows:
./dropone -p some_positive_integer (add -q the first time)
./takeone
and try some of the tests described above the sources.

2) Working with queue attributes. This creates a queue with custom attributes, and also tries to modify them at a later time. Look for what attributes are ignored, when and why.
/*
 *  msgqattrs.c
 *  
 *  creates a posix message queue requesting custom attributes,
 *  and displays what attributes are taken into account and what
 *  are not, while both creating and while setting at a later time.
 *
 *
 *  Created by Mij <mij@bitchx.it> on 31/08/05.
 *  Original source file available on http://mij.oltrelinux.com/devel/unixprg/
 *
 */


#include <stdio.h>
#include <mqueue.h>
#include <sys/stat.h>
/* exit() */
#include <stdlib.h>


#define MSGQOBJ_NAME        "/fooasd1431"
#define MAX_QMSG_SIZE       30


int main(int argc, char *argv[]) {
    mqd_t myqueue;
    struct mq_attr wanted_attrs, actual_attrs;
    
        
    /* filling the attribute structure */
    wanted_attrs.mq_flags = 0;                    /* no exceptional behavior (just O_NONBLOCK currently available)  */
    wanted_attrs.mq_maxmsg = 100;                 /* room for at most 100 messages in the queue */
    wanted_attrs.mq_msgsize = MAX_QMSG_SIZE;      /* maximum size of a message */
    wanted_attrs.mq_curmsgs = 123;                /* this (current number of messages) will be ignored */
    
    /* mq_open() for creating a new queue (using default attributes) */
    myqueue = mq_open(MSGQOBJ_NAME, O_RDWR | O_CREAT | O_EXCL, S_IRWXU | S_IRWXG, &wanted_attrs);
    if (myqueue == (mqd_t)-1) {
        perror("In mq_open()");
        exit(1);
    }

    printf("Message queue created.\n");
    
    /* getting queue attributes after creation          --  mq_getattr()    */
    mq_getattr(myqueue, &actual_attrs);
    printf("Attributes right after queue creation:\n\t- non blocking flag: %d\n\t- maximum number of messages: %ld\n\t- maximum size of a message: %ld\n\t- current number of messages: %ld\n", (actual_attrs.mq_flags == 0 ? 0 : 1), actual_attrs.mq_maxmsg, actual_attrs.mq_msgsize, actual_attrs.mq_curmsgs);
    
    /* building the structure again for modifying the existent queue */
    wanted_attrs.mq_flags = O_NONBLOCK;
    wanted_attrs.mq_maxmsg = 350;               /* this will be ignored by mq_setattr() */
    wanted_attrs.mq_msgsize = MAX_QMSG_SIZE;    /* this will be ignored by mq_setattr() */
    wanted_attrs.mq_curmsgs = 123;              /* this will be ignored by mq_setattr() */
    
    /* trying to later set different attributes on the queue        --  mq_setattr()    */
    mq_setattr(myqueue, &wanted_attrs, NULL);
    
    /* getting queue attributes after creation */
    mq_getattr(myqueue, &actual_attrs);
    printf("Attributes after setattr():\n\t- non blocking flag: %d\n\t- maximum number of messages: %ld\n\t- maximum size of a message: %ld\n\t- current number of messages: %ld\n", (actual_attrs.mq_flags == 0 ? 0 : 1), actual_attrs.mq_maxmsg, actual_attrs.mq_msgsize, actual_attrs.mq_curmsgs);
    
    /* removing the queue from the system       --  mq_unlink() */
    mq_unlink(MSGQOBJ_NAME);
    
    
    return 0;
}

You can download the original ascii source with this link: msgqattrs.c.
Compile with:
gcc --pedantic -Wall -o msgqattrs msgqattrs.c
Run with: ./msgqattrs

IPC: POSIX Semaphores


Notes:
In the real world today, POSIX semaphores don't still get full support from OSes. Some features are not yet implemented. The Web is nonetheless poor of documentation about it, so the goal here is to leave some concepts; you will map into this or the other implementation in the need. We'll hopefully enjoy better support during the next years.
Semaphores are a mechanism for controlling access to shared resources. In their original form, they are associated to a single resource, and contain a binary value: {free, busy}. If the resource is shared between more threads (or procs), each thread waits for the resource semaphore to switch free. At this time, it sets the semaphore to busy and enters the critical region, accessing the resource. Once the work is done with the resource, the process releases it back setting the semaphore to free. The whole thing works because the semaphore value is set directly by the kernel on request, so it's not subject to process interleaving.
Please mind that this mechanism doesn't provide mutex access to a resource. It just provides support for processes to carry out the job themselves, so it's completely up to the processes to take the semaphore up to date and access the resource in respect of it.
Semaphores can be easily extended to support several accesses to a resource. If a resource can be accessed concurrently by n threads, the semaphore simply needs to hold an integer value instead of a Boolean one. This integer would be initialized to n, and each time it's positive value a process decrements it by 1 and gets 1 slot in the resource. When the value reaches 0, no more slots are available and candidate threads have to wait for the resource to get available ("free" is no more appropriate in this case). In this case the semaphore is told to be locked.
This is the concept behind semaphores. Dijkstra has been inspired by actual train semaphores when he designed them in '60s: this justify their being very intuitive.
There are 2 relevant APIs for such systems today: The former implementations being inherited by the System V, and the latter being standardized by POSIX 1003.1b (year 1993, the first one with real time extensions). SysV semaphores are older and more popular. POSIX ones are newer, cleaner, easier, and lighter against the machine.
Just like pipes, semaphores can be named or unnamed. Unnamed semaphores can only be shared by related processes. The POSIX API defines both these personalities. They just differ in creation and opening.

Summary:

Examples:
1) Unnamed semaphores.
One process; the main thread creates 2 threads. They access their critical section with mutual exclusion. The first one synchronously, the second one asynchronously.
/*
 *  semaphore.c
 *  
 *
 *  Created by Mij <mij@bitchx.it> on 12/03/05.
 *  Original source file available at http://mij.oltrelinux.com/devel/unixprg/
 *
 */


#define _POSIX_SOURCE
#include <stdio.h>
/* sleep() */
#include <errno.h>
#include <unistd.h>
/* abort() and random stuff */
#include <stdlib.h>
/* time() */
#include <time.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>


/* this skips program termination when receiving signals */
void signal_handler(int type);

/*
 * thread A is synchronous. When it needs to enter its
 * critical section, it can't do anything other than waiting.
 */
void *thread_a(void *);

/*
 * thread B is asynchronous. When it tries to enter its
 * critical section, it switches back to other tasks if
 * it hasn't this availability.
 */
void *thread_b(void *);


/* the semaphore */
sem_t mysem;

int main(int argc, char *argv[])
{
    pthread_t mytr_a, mytr_b;
    int ret;
    
    
    srand(time(NULL));
    signal(SIGHUP, signal_handler);
    signal(SIGUSR1, signal_handler);

    /*
     * creating the unnamed, local semaphore, and initialize it with
     * value 1 (max concurrency 1)
     */
    ret = sem_init(&mysem, 0, 1);
    if (ret != 0) {
        /* error. errno has been set */
        perror("Unable to initialize the semaphore");
        abort();
    }
    
    /* creating the first thread (A) */
    ret = pthread_create(&mytr_a, NULL, thread_a, NULL);
    if (ret != 0) {
        perror("Unable to create thread");
        abort();
    }

    /* creating the second thread (B) */
    ret = pthread_create(&mytr_b, NULL, thread_b, NULL);
    if (ret != 0) {
        perror("Unable to create thread");
        abort();
    }
    
    /* waiting for thread_a to finish */
    ret = pthread_join(mytr_a, (void *)NULL);
    if (ret != 0) {
        perror("Error in pthread_join");
        abort();
    }

    /* waiting for thread_b to finish */
    ret = pthread_join(mytr_b, NULL);
    if (ret != 0) {
        perror("Error in pthread_join");
        abort();
    }

    return 0;
}


void *thread_a(void *x)
{
    unsigned int i, num;
    int ret;
    
    
    printf(" -- thread A -- starting\n");
    num = ((unsigned int)rand() % 40);
    
    /* this does (do_normal_stuff, do_critical_stuff) n times */
    for (i = 0; i < num; i++) {
        /* do normal stuff */
        sleep(3 + (rand() % 5));
        
        /* need to enter critical section */
        printf(" -- thread A -- waiting to enter critical section\n");
        /* looping until the lock is acquired */
        do {
            ret = sem_wait(&mysem);
            if (ret != 0) {
                /* the lock wasn't acquired */
                if (errno != EINVAL) {
                    perror(" -- thread A -- Error in sem_wait. terminating -> ");
                    pthread_exit(NULL);
                } else {
                    /* sem_wait() has been interrupted by a signal: looping again */
                    printf(" -- thread A -- sem_wait interrupted. Trying again for the lock...\n");
                }
            }
        } while (ret != 0);
        printf(" -- thread A -- lock acquired. Enter critical section\n");
        
        /* CRITICAL SECTION */
        sleep(rand() % 2);
        
        /* done, now unlocking the semaphore */
        printf(" -- thread A -- leaving critical section\n");
        ret = sem_post(&mysem);
        if (ret != 0) {
            perror(" -- thread A -- Error in sem_post");
            pthread_exit(NULL);
        }
    }
    
    printf(" -- thread A -- closing up\n");

    pthread_exit(NULL);
}


void *thread_b(void *x)
{
    unsigned int i, num;
    int ret;
    
    
    printf(" -- thread B -- starting\n");
    num = ((unsigned int)rand() % 100);
    
    /* this does (do_normal_stuff, do_critical_stuff) n times */
    for (i = 0; i < num; i++) {
        /* do normal stuff */
        sleep(3 + (rand() % 5));
        
        /* wants to enter the critical section */
        ret = sem_trywait(&mysem);
        if (ret != 0) {
            /* either an error happened, or the semaphore is locked */
            if (errno != EAGAIN) {
                /* an event different from "the semaphore was locked" happened */
                perror(" -- thread B -- error in sem_trywait. terminating -> ");
                pthread_exit(NULL);
            }
            
            printf(" -- thread B -- cannot enter critical section: semaphore locked\n");
        } else {
            /* CRITICAL SECTION */
            printf(" -- thread B -- enter critical section\n");

            sleep(rand() % 10);
            
            /* done, now unlocking the semaphore */
            printf(" -- thread B -- leaving critical section\n");
            sem_post(&mysem);
        }
    }
    
    printf(" -- thread B -- closing up\n");
    
    /* joining main() */
    pthread_exit(NULL);
}


void signal_handler(int type)
{
    /* do nothing */
    printf("process got signal %d\n", type);
    return;
}

You can download the original ascii source with this link: semaphore.c.
Compile with: gcc --pedantic -Wall -o semaphore semaphore.c
Run with: ./semaphore


IPC: POSIX shared memory


Notes:
Shared memory is what the name says about it: a segment of memory shared between several processes. UNIX knows System V shared memory and POSIX shared memory. This covers the POSIX way, but the other one is just matter of different system call names for initializing and terminating the segment.
Shared memory in UNIX is based on the concept of memory mapping. The segment of memory shared is coupled with an actual file in the filesystem. The file content is (ideally) a mirror of the memory segment at any time. The mapping between the shared segment content and the mapped file is persistent. The mapped file can be moved (even replicated) arbitrarily; this turns often suitable for reimporting such image of the memory segment across different runs of the same process (or different ones too) [See Further notes on mapping, below].
In fact, keeping an image file of the memory segment is occasionally useless. Anonymous mapping is when a shared segment isn't mapped to any actual object in the filesystem. This behavior is requested either explicitly (BSD way) or via /dev/zero, depending on the implementation [See Further notes on anonymous mapping, below].
In POSIX shared memory, the memory segment is mapped onto a posix object; consequently, it suffers the same problem discussed in notes on POSIX objects below. The shm_open() function is used to create such object (or open an existing one). The core function mmap() is then used to actually attach a memory segment of user-defined size into the address space of the process and map its content to the one of the ipc object (in case of open existing object, the former content is also imported). Thereafter, if other processes shm_open and mmap the same memory object, the memory segment will be effectively shared.
Please mind that shared memory is natural when working with threads in place of tasks. Threading is frequently used as a quick quirk when shared memory is wanted. Similarly, programming with shared memory requires many of the programmer attentions discussed for threads: usually shared memory is used in conjunction with some form of synchronization, often semaphores.
A segment of memory mapped into a process' address space will never be detached unless the munmap() is called. A posix shared memory object will persist unless the shm_unlink() function is used (or manually removed from the filesystem, where possible).
Figure 1 Figure 2
Further notes on mapping:
The mmap function maps objects into the process' address space. Mmap does two things: it causes the kernel to allocate and attach to the process address space a suitable number of page for covering the size requested by the user, and it establish the mapping between the object content and the memory content.
When mmap is called, the kernel allocates a suitable number of pages to cover the size requested by the user. Being memory allocation quantized, the real memory allocated into the process address space is rarely large what the user asked for. In contrast, files on disk can be stretched to whatever size byte by byte. Several effects raise from this fact. Figure 1 illustrates what happens when the memory segment size and mapped file size requested are equal, but not multiple of the page size. Figure 2 shows what happens when the size of the mapped file is shorter than the size requested for the memory segment.

Further notes on anonymous mapping:
Anonymous mapping is used share memory segment without mapping it to a persistent object (posix object, or file). It is the shared memory counterpart of unnamed semaphores, pipes etc. With this role, it is clear that anonymous mapping can only occur between related processes. From this mechanism, shared memory benefits in terms of performance. The developer is also advantaged not having to handle any persistent object.
There are 2 ways to get anonymous memory mapping. BSD provides a special flag (MAP_ANON) for mmap() to state this wish explicitly. Linux implements the same feature since version 2.4, but in general this is not a portable way to carry out the job.
System V (SVR4) doesn't provided such method, but the /dev/zero file can be used for the same purpose. Upon opening, the memory segment is initialized with the content read from the file (which is always 0s for this special file). Hereafter, whatever the kernel will write on the special file for mirroring from memory will be just discarded by the kernel.

Summary:

Examples:
1) Two processes: a server creates a mapped memory segment and produces a message on it, then terminates. The client opens the persistent object mapping that memory and reads back the message left. The mapped object acts like a persistent memory image in this example.
/*
 *  shm_msgserver.c
 *  
 *  Illustrates memory mapping and persistence, with POSIX objects.
 *  This process produces a message leaving it in a shared segment.
 *  The segment is mapped in a persistent object meant to be subsequently
 *  open by a shared memory "client".
 *
 *
 *  Created by Mij <mij@bitchx.it> on 27/08/05.
 *  Original source file available at http://mij.oltrelinux.com/devel/unixprg/
 *
 */


#include <stdio.h>
/* shm_* stuff, and mmap() */
#include <sys/mman.h>
#include <sys/types.h>
/* exit() etc */
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
/* for random() stuff */
#include <stdlib.h>
#include <time.h>


/* Posix IPC object name [system dependant] - see
http://mij.oltrelinux.com/devel/unixprg/index2.html#ipc__posix_objects */
#define SHMOBJ_PATH         "/foo1423"
/* maximum length of the content of the message */
#define MAX_MSG_LENGTH      50
/* how many types of messages we recognize (fantasy) */
#define TYPES               8

/* message structure for messages in the shared segment */
struct msg_s {
    int type;
    char content[MAX_MSG_LENGTH];
};


int main(int argc, char *argv[]) {
    int shmfd;
    int shared_seg_size = (1 * sizeof(struct msg_s));   /* want shared segment capable of storing 1 message */
    struct msg_s *shared_msg;      /* the shared segment, and head of the messages list */
    

    /* creating the shared memory object    --  shm_open()  */
    shmfd = shm_open(SHMOBJ_PATH, O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
    if (shmfd < 0) {
        perror("In shm_open()");
        exit(1);
    }
    fprintf(stderr, "Created shared memory object %s\n", SHMOBJ_PATH);
    
    /* adjusting mapped file size (make room for the whole segment to map)      --  ftruncate() */
    ftruncate(shmfd, shared_seg_size);

    /* requesting the shared segment    --  mmap() */    
    shared_msg = (struct msg_s *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
    if (shared_msg == NULL) {
        perror("In mmap()");
        exit(1);
    }
    fprintf(stderr, "Shared memory segment allocated correctly (%d bytes).\n", shared_seg_size);

    
    srandom(time(NULL));
    /* producing a message on the shared segment */
    shared_msg->type = random() % TYPES;
    snprintf(shared_msg->content, MAX_MSG_LENGTH, "My message, type %d, num %ld", shared_msg->type, random());

   
    /* [uncomment if you wish] requesting the removal of the shm object     --  shm_unlink() */
/*
    if (shm_unlink(SHMOBJ_PATH) != 0) {
        perror("In shm_unlink()");
        exit(1);
    }
*/

    return 0;
}

/*
 *  shm_msgclient.c
 *  
 *  Illustrates memory mapping and persistence, with POSIX objects.
 *  This process reads and displays a message left it in "memory segment
 *  image", a file been mapped from a memory segment.
 *
 *
 *  Created by Mij <mij@bitchx.it> on 27/08/05.
 *  Original source file available at http://mij.oltrelinux.com/devel/unixprg/
 *
 */

#include <stdio.h>
/* exit() etc */
#include <unistd.h>
/* shm_* stuff, and mmap() */
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
/* for random() stuff */
#include <stdlib.h>
#include <time.h>


/* Posix IPC object name [system dependant] - see
http://mij.oltrelinux.com/devel/unixprg/index2.html#ipc__posix_objects */
#define SHMOBJ_PATH         "/foo1423"      
/* maximum length of the content of the message */
#define MAX_MSG_LENGTH      50
/* how many types of messages we recognize (fantasy) */
#define TYPES               8

/* message structure for messages in the shared segment */
struct msg_s {
    int type;
    char content[MAX_MSG_LENGTH];
};


int main(int argc, char *argv[]) {
    int shmfd;
    int shared_seg_size = (1 * sizeof(struct msg_s));   /* want shared segment capable of storing 1 message */
    struct msg_s *shared_msg;      /* the shared segment, and head of the messages list */
    

    /* creating the shared memory object    --  shm_open()  */
    shmfd = shm_open(SHMOBJ_PATH, O_RDWR, S_IRWXU | S_IRWXG);
    if (shmfd < 0) {
        perror("In shm_open()");
        exit(1);
    }
    printf("Created shared memory object %s\n", SHMOBJ_PATH);
    
    /* requesting the shared segment    --  mmap() */    
    shared_msg = (struct msg_s *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
    if (shared_msg == NULL) {
        perror("In mmap()");
        exit(1);
    }
    printf("Shared memory segment allocated correctly (%d bytes).\n", shared_seg_size);


    printf("Message type is %d, content is: %s\n", shared_msg->type, shared_msg->content);
    
    return 0;
}

You can download the original ascii source files with these links: shm_msgclient.c and shm_msgserver.c.
Compile with:
gcc --ansi --Wall -o shm_msgserver shm_msgserver.c and
gcc --ansi --Wall -o shm_msgclient shm_msgclient.c
(some systems wrap these functions into a posix realtime library: add -lrt for them -- e.g. Linux does)
Run the following:
./shm_msgserver
./shm_msgclient


2) Example on BSD asonymous memory mapping. The process gets a semaphore, establishes an anonymous memory mapping and forks (so the data space get independent). Both the parent and the child, in mutex, update the value of the shared segment by random quantities.
/*
 *  shm_anon_bsd.c
 *  
 *  Anonymous shared memory via BSD's MAP_ANON.
 *  Create a semaphore, create an anonymous memory segment with the MAP_ANON
 *  BSD flag and loop updating the segment content (increment casually) with
 *  short intervals.
 *
 *
 *  Created by Mij <mij@bitchx.it> on 29/08/05.
 *  Original source file available at http://mij.oltrelinux.com/devel/unixprg/
 *
 */

#include <stdio.h>
/* for shm_* and mmap() */
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
/* for getpid() */
#include <unistd.h>
/* exit() */
#include <stdlib.h>
/* for sem_* functions */
#include <sys/stat.h>
#include <semaphore.h>
/* for seeding time() */
#include <time.h>

/* name of the semaphore */
#define     SEMOBJ_NAME         "/semshm"
/* maximum number of seconds to sleep between each loop operation */
#define     MAX_SLEEP_SECS      3
/* maximum value to increment the counter by */
#define     MAX_INC_VALUE       10 


int main(int argc, char *argv[]) {
    int shmfd;
    int shared_seg_size = 2 * sizeof(int);
    int *shared_values;     /* this will be a (shared) array of 2 elements */
    sem_t *sem_shmsegment;  /* semaphore controlling access to the shared segment */
    pid_t mypid;
    
    
    /* getting a new semaphore for the shared segment       -- sem_open()   */
    sem_shmsegment = sem_open(SEMOBJ_NAME, O_CREAT | O_EXCL, S_IRWXU | S_IRWXG, 1);
    if ((int)sem_shmsegment == SEM_FAILED) {
        perror("In sem_open()");
        exit(1);
    }
    /* requesting the semaphore not to be held when completely unreferenced */
    sem_unlink(SEMOBJ_NAME);
    
    /* requesting the shared segment    --  mmap() */    
    shared_values = (int *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
    if ((int)shared_values == -1) {
        perror("In mmap()");
        exit(1);
    }
    fprintf(stderr, "Shared memory segment allocated correctly (%d bytes) at %u.\n", shared_seg_size, (unsigned int)shared_values);
    close(shmfd);


    /* dupping the process */
    if (! fork() )
        /* the child waits 2 seconds for better seeding srandom() */
        sleep(2);
    
    /* seeding the random number generator (% x for better seeding when child executes close) */
    srandom(time(NULL));

    /* getting my pid, and introducing myself */
    mypid = getpid();
    printf("My pid is %d\n", mypid);    

    /*
       main loop:
        - pause
        - print the old value
        - choose (and store) a random quantity
        - increment the segment by that
    */
    do {
        sleep(random() % (MAX_SLEEP_SECS+1));       /* pausing for at most MAX_SLEEP_SECS seconds */
        
        sem_wait(sem_shmsegment);
        /* entered the critical region */
        
        printf("process %d. Former value %d.", mypid, shared_values[0]);
        
        shared_values[1] = random() % (MAX_INC_VALUE+1);            /* choose a random value up to MAX_INC_VALUE */
        shared_values[0] += shared_values[1];   /* and increment the first cell by this value */
        
        printf(" Incrementing by %d.\n", shared_values[1]);

        /* leaving the critical region */
        sem_post(sem_shmsegment);
    } while (1);
    
    /* freeing the reference to the semaphore */
    sem_close(sem_shmsegment);

    
    return 0;
}

You can download the original ascii source with this link: shm_anon_bsd.c.
Compile with:
gcc --Wall -lrt -o shm_anon_bsd shm_anon_bsd.c
Run the following: ./shm_anon_bsd

IPC: notes on POSIX objects -- the POSIX objects mess

Notes: The POSIX API makes frequent use of "posix objects". Posix objects are for instance semaphores, shared memory segments or message queues. From the programmer point of view, they are simply referenced by an identificator, which is a string: the POSIX object name.
POSIX objects come in play when persistence is required. In the semaphore example, the value of the semaphore needs to be preserved across system reboots. A program can create those objects and recall them during a later execution by their name.
The problem while using POSIX objects is actually their naming. Posix.1 (1003.1-1996) rules the following about posix object names: For Posix, as you see, object names and (filesystem) pathnames are friend (naming rules and heading slash). But mapping them in the actual filesystem is not pointed out anywhere. The effect is that several different approaches to this mapping evolved until today, and the whole mechanism itself is non-portable. For example, FreeBSD 5 maps these objects directly into the file system (the semaphore named "/tmp/foo" is the actual file "foo" in /tmp), while Linux maps them usually under "/dev/shm" (message queue "foo" is file /dev/shm/foo).
Using only one slash, heading, complies to the rules but does not help for implementations which maps directly to the filesystem, in which the process wouldn't probably have write permission to the root directory where the object would be stored. The whole standard covering IPC objects naming is useless, there's no portable solution; the developer might use tools like autoconf to decide what name to choose at compile time, on the basis of the OS for which the code is compiled. A simple solution is to use a "template" name, and possibly prefixing it on architectures that map posix object names directly to the filesystem.