冉's profileDays of our lifePhotosBlogListsMore Tools Help

冉 孟

Occupation
Working for Sun Microsystems

J9

March 07

一张让人受不了的照片

过年时在家有段时间实在是无聊,把带回去的本科毕业时的光盘拿了出来第一次审阅了一下,结果在其中发现了这么一张照片,哈哈.遥想当年花一样的年华啊.

今年春天最流行什么?

结婚.那天一不留神回学校吃了一个午饭,然后一不留神碰到了toad贤伉俪,然后又一个不留神被告知他马上就要和Jasy登记结婚了. 太突然了,以致于我正在继续进行的从早上开始的关于我是否已经长大成人的思考被残酷的扼杀掉了.然后那一天的后一天,我和张钋聊天,又被残酷的告知许总已经结婚了,错愕之余我终于发现了,结婚,这就是今春的流行.刚刚能够从家里上网就从toad那里搞到了一些结婚照,哈哈,贴之(已获授权).
January 14

Makefile howto

How to write a Makefile
Introduction
Make is one of the original Unix tools for Software Engineering. By S.I. Feldman of AT&T Bell Labs circa 1975. But there are public domain versions (eg. GNU) and versions for other systems (eg. Vax/VMS).
Related tools are the language compilers (cc, f77, lex, yacc, etc.) and shell programming tools (eg. awk, sed, cp, rm, etc.). You need to know how to use these.
Important adjuncts are lint (source code checking for obvious errors) ctags (locate functions, etc. in source code) and mkdepend. These are nice, and good programmers use them.
Important, and related tools, are the software revision systems SCCS (Source Code Control System) and RCS (Revision Control System -- the recommended choice)
The idea is to automate and optimize the construction of programs/files -- ie. to leave enough foot prints so that others can follow.
Makefile Naming
make is going to look for a file called Makefile, if not found then a file called makefile. Use the first (so the name stands out in listings).
You can get away without any Makefile (but shouldn't)! Make has default rules it knows about.
Makefile Components
Comments
Comments are any text beginning with the pound (#) sign. A comment can start anywhere on a line and continue until the end of the line. For example:
# $Id: slides,v 1.2 1992/02/14 21:00:58 reggers Exp $
Macros
Make has a simple macro definition and substitution mechanism. Macros are defined in a Makefile as = pairs. For example:
MACROS=  -me
PSROFF=  groff -Tps
DITROFF= groff -Tdvi
CFLAGS= -O -systype bsd43
There are lots of default macros -- you should honor the existing naming conventions. To find out what rules/macros make is using type:
% make -p
NOTE: That your environment variables are exported into the make as macros. They will override the defaults.
You can set macros on the make command line:
% make "CFLAGS= -O" "LDFLAGS=-s" printenv
   cc -O printenv.c -s -o printenv
Targets
You make a particular target (eg. make all), in none specified then the first target found:
paper.dvi: $(SRCS)
       $(DITROFF) $(MACROS) $(SRCS) >paper.dvi
NOTE: The the line beginning with $(DITROFF) begins with TAB not spaces.
The target is made if any of the dependent files have changed. The dependent files in this case are represented by the $(SRCS) statement.
Continuation of Lines
Use a back slash (\). This is important for long macros and/or rules.

Conventional Macros
There are lots of default macros (type "make -p" to print out the defaults). Most are pretty obvious from the rules in which they are used:
AR = ar
GFLAGS =
GET = get
ASFLAGS =
MAS = mas
AS = as
FC = f77
CFLAGS =
CC = cc
LDFLAGS =
LD = ld
LFLAGS =
LEX = lex
YFLAGS =
YACC = yacc
LOADLIBS =
MAKE = make
MAKEARGS = 'SHELL=/bin/sh'
SHELL = /bin/sh
MAKEFLAGS = b
Special Macros
Before issuing any command in a target rule set there are certain special macros predefined.

$@ is the name of the file to be made.
$? is the names of the changed dependents.
So, for example, we could use a rule
printenv: printenv.c
        $(CC) $(CFLAGS) $? $(LDFLAGS) -o $@
alternatively:
printenv: printenv.c
        $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@
There are two more special macros used in implicit rules. They are:
$< the name of the related file that caused the action.
$* the prefix shared by target and dependent files.
Makefile Target Rules
The general syntax of a Makefile Target Rule is
    target [target...] : [dependent ....]
    [ command ...]
Items in brackets are optional, ellipsis means one or more. Note the tab to preface each command is required.
The semantics is pretty simple. When you say "make target" make finds the target rule that applies and, if any of the dependents are newer than the target, make executes the com- mands one at a time (after macro substitution). If any dependents have to be made, that happens first (so you have a recursion).
A make will terminate if any command returns a failure sta- tus. That's why you see rules like:
clean:
        -rm *.o *~ core paper
Make ignores the returned status on command lines that begin with a dash. eg. who cares if there is no core file?
Make will echo the commands, after macro substition to show you what's happening as it happens. Sometimes you might want to turn that off. For example:
install:
        @echo You must be root to install
Example Target Rules
For example, to manage sources stored within RCS (sometimes you'll need to "check out" a source file):
SRCS=x.c y.c z.c
$(SRCS):
        co $@
To manage sources stored within SCCS (sometimes you'll need to "get" a source file):
$(SRCS):
        sccs get $@
Alternativley, to manage sources stored within SCCS or RCS let's generalize with a macro that we can set as required.
SRCS=x.c y.c z.c
# GET= sccs get
GET= co
$(SRCS):
        $(GET) $@
For example, to construct a library of object files
lib.a: x.o y.o z.o
        ar rvu lib.a x.o y.o z.o
        ranlib lib.a
Alternatively, to be a bit more fancy you could use:
OBJ=x.o y.o z.o
AR=ar
lib.a: $(OBJ)
        $(AR) rvu $@ $(OBJ)
        ranlib $@
Since AR is a default macro already assigned to "ar" you can get away without defining it (but shouldn't).
If you get used to using macros you'll be able to make a few rules that you can use over and over again.
For example, to construct a library in some other directory
INC=../misc
OTHERS=../misc/lib.a
$(OTHERS):
        cd $(INC); make lib.a
Beware:, the following will not work (but you'd think it should)
INC=../misc
OTHERS=../misc/lib.a
$(OTHERS):
        cd $(INC)
        make lib.a
Each command in the target rule is executed in a separate shell. This makes for some interesting constructs and long continuation lines.
To generate a tags file
SRCS=x.c y.c z.c
CTAGS=ctags -x >tags
tags:   $(SRCS)
        ${CTAGS} $(SRCS)
On large projects a tags file, that lists all functions and their invocations is a handy tool.
To generate a listing of likely bugs in your problems
lint:
        lint $(CFLAGS) $(SRCS)
Lint is a really good tool for finding those obvious bugs that slip into programs -- eg. type classes, bad argu- ment list, etc.
Some Basic Make Rule
People have come to expect certain targets in Makefiles. You should always browse first, but it's reasonable to expect that the targets all (or just make), install, and clean will be found.

make all -- should compile everything so that you can do local testing before installing things.
make install -- should install things in the right places. But watch out that things are installed in the right place for your system.
make clean -- should clean things up. Get rid of the executables, any temporary files, object files, etc.
You may encounter other common targets, some have been already mentioned (tags and lint).

An Example Makefile for printenv
# make the printenv command
#
OWNER=bin
GROUP=bin
CTAGS= ctags -x >tags
CFLAGS= -O
LDFLAGS= -s
CC=cc
GET=co
SRCS=printenv.c
OBJS=printenv.o
SHAR=shar
MANDIR=/usr/man/manl/printenv.l
BINDIR=/usr/local/bin
DEPEND= makedepend $(CFLAGS)
all:    printenv
# To get things out of the revision control system
$(SRCS):
        $(GET) $@
# To make an object from source
       $(CC) $(CFLAGS) -c $*.c
# To make an executable
printenv: $(OBJS)
        $(CC) $(LDFLAGS) -o $@ $(OBJS)
# To install things in the right place
install: printenv printenv.man
        $(INSTALL) -c -o $(OWNER) -g $(GROUP) -m 755 printenv $(BINDIR)
        $(INSTALL) -c -o $(OWNER) -g $(GROUP) -m 644 printenv.man $(MANDIR)
# where are functions/procedures?
tags: $(SRCS)
        $(CTAGS) $(SRCS)
# what have I done wrong?
lint: $(SRCS)
        lint $(CFLAGS) $(SRCS)
# what are the source dependencies
depend: $(SRCS)
        $(DEPEND) $(SRCS)
# to make a shar distribution
shar:   clean
        $(SHAR) README Makefile printenv.man $(SRCS) >shar
# clean out the dross
clean:
        -rm printenv *~ *.o *.bak core tags shar
# DO NOT DELETE THIS LINE -- make depend depends on it.
printenv.o: /usr/include/stdio.h
Makefile Implicit Rules
Consider the rule we used for printenv
printenv: printenv.c
        $(CC) $(CFLAGS) printenv.c $(LDFLAGS) -o printenv
We generalized a bit to get
printenv: printenv.c
        $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@
The command is one that ought to work in all cases where we build an executable x out of the source code x.c This can be stated as an implicit rule:
.c:
        $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@
This Implicit rule says how to make x out of x.c -- run cc on x.c and call the output x. The rule is implicit because no particular target is mentioned. It can be used in all cases.
Another common implicit rule is for the construction of .o (object) files out of .c (source files).
.o.c:
        $(CC) $(CFLAGS) -c $<
alternatively
.o.c:
        $(CC) $(CFLAGS) -c $*.c
Make Dependencies
It's pretty common to have source code that uses include files. For example:
% cat program.c
#include       
#include        "defs.h"
#include        "glob.h"
        etc....
main(argc,argv)
        etc...
The implicit rule only covers part of the source code depen- dency (it only knows that program.o depends on program.c). The usual method for handling this is to list the dependen- cies separately;
        etc...
        $(CC) $(CFLAGS) -c $*.c
        etc...
program.o: program.c defs.h glob.h
Usually an implicit rule and a separate list of dependencies is all you need. And it ought to be easy enough to figure out what the dependencies are.
However, there are a number of nice tools around that will automatically generate dependency lists for you. For example (trivial):
DEPEND= makedepend $(CFLAGS)
        etc...
# what are the source dependencies
depend: $(SRCS)
        $(DEPEND) $(SRCS)
        etc....
# DO NOT DELETE THIS LINE -- ....
printenv.o: /usr/include/stdio.h
These tools (mkdepend, mkmkf, etc.) are very common these days and aren't too difficult to use or understand. They're just shell scripts that run cpp (or cc -M, or etc.) to find out what all the include dependencies are. They then just tack the dependency list onto the end of the Makefile.
Based on Make and Makefiles by
Reg Quinton
Computing and Communications Services
The University of Western Ontario
London, Ontario N6A 5B7
Canada

--------------------------------------------------------------------------------
Press here to return to the General Unix Software Menu.

Signal Basic

1. What is the signal?
A signal is an asynchronous notification of an event. A sig-
     nal  is said to be generated for (or sent to) a process when
     the event associated with that signal first occurs. Examples
     of such events include hardware faults, timer expiration and
     terminal activity, as well as the invocation of the  kill(2)
     or  sigsend(2)  functions.   In some circumstances, the same
     event generates signals for multiple  processes.  A  process
     may  request  a  detailed  notification of the source of the
     signal  and  the  reason   why   it   was   generated.   See
     siginfo.h(3HEAD).
2. Who generates signals and who receives those signals?
Signals can be generated  synchronously  or  asynchronously.
     1) Events directly caused by the execution of code by a thread,
     such as a reference to an unmapped, protected, or bad memory
     can  generate  SIGSEGV or SIGBUS; a floating point exception
     can generate   SIGFPE;  and  the  execution  of  an  illegal
     instruction can generate SIGILL. Such events are referred to
     as traps; signals generated by traps are said to be synchro-
     nously  generated.  Synchronously generated signals are ini-
     tiated by a specific thread and are delivered to and handled
     by that thread.
    
     2) Signals may also be generated by calling kill(), sigqueue(),
     or  sigsend().  Events  such as keyboard interrupts generate
     signals, such as SIGINT, which are sent to the  target  pro-
     cess.  Such  events  are  referred to as interrupts; signals
     generated by interrupts are said to be  asynchronously  gen-
     erated.
3. What the receiver should do?
     A signal is said to be delivered to a process when a  thread
     within  the  process  takes  the appropriate action for  the
     disposition of the signal.  Delivery  of  a  signal  can  be
     blocked.  There  are  two methods for handling delivery of a
     signal in a  multithreaded  application.  The  first  method
     specifies a signal handler function to execute when the sig-
     nal is received by the process. See sigaction(2). The second
     method  uses  sigwait(2)  to  create  a thread to handle the
     receipt of the signal. The sigaction() function can be  used
     for both synchronously and asynchronously generated signals.
     The sigwait() function will  work  only  for  asynchronously
     generated  signals,  as  synchronously generated signals are
     sent to the thread that  caused  the  event.  The  sigwait()
     function  is  the  recommended  for use with a multithreaded
     application.
4. SIGNAL MASK
     Each thread has a signal mask  that defines the set of  sig-
     nals  currently blocked from delivery to it. The signal mask
     of the main thread is inherited from the signal mask of  the
     thread  that created it in the parent process. The selection
     of the thread  within  the  process  that  is  to  take  the
     appropriate  action for the signal is based on the method of
     signal generation and the signal masks of the threads in the
     receiving process.
5. key syscalls
signal() and sigset()
    
The signal() and sigset() functions modify  signal  disposi-
     tions.  The  sig argument specifies the signal, which may be
     any signal except SIGKILL and  SIGSTOP.  The  disp  argument
     specifies  the  signal's  disposition, which may be SIG_DFL,
     SIG_IGN, or the address of a signal handler. If signal()  is
     used,  disp  is  the address of a signal handler, and sig is
     not  SIGILL, SIGTRAP, or  SIGPWR, the system first sets  the
     signal's disposition to  SIG_DFL before executing the signal
     handler. If sigset() is used and disp is the  address  of  a
     signal handler, the system adds sig to the calling process's
     signal  mask before executing the signal handler;  when  the
     signal  handler  returns,  the  system  restores the calling
     process's signal mask to its state prior to the delivery  of
     the  signal.  In  addition,  if sigset() is used and disp is
     equal to  SIG_HOLD, sig is added to  the  calling  process's
     signal mask and the signal's disposition remains unchanged.
     The  sigrelse()  function  removes  sig  from  the   calling
     process's signal mask.
     The sigignore() function sets  the  disposition  of  sig  to
     SIG_IGN.
     The  sigpause()  function  removes  sig  from  the   calling
     process's  signal  mask   and  suspends  the calling process
     until a signal is received.
The sigaction() function allows the calling process to exam-
     ine  or  specify  the  action  to  be taken on delivery of a
     specific signal. See signal.h(3HEAD) for an  explanation  of
     general signal concepts.
The sigwait() function selects a signal in set that is pend-
     ing   on   the   calling   thread  (see  thr_create(3C)  and
     pthread_create(3C).)

Thread Basic


Threads: Basic Theory and Libraries
This chapter examines aspects of threads and multiprocessing (and multithreading). We will firts study a little theory of threads and also look at how threading can be effectively used to make programs more efficient. The C thread libraries will then be introduced. The following chapters will look at further thead issues sucj a synchronisation and practical examples.

Processes and Threads
We can think of a thread as basically a lightweight process. In order to understand this let us consider the two main characteristics of a process:

Unit of resource ownership
-- A process is allocated:
a virtual address space to hold the process image
control of some resources (files, I/O devices...)
Unit of dispatching
- A process is an execution path through one or more programs:
execution may be interleaved with other processes
the process has an execution state and a dispatching priority
If we treat these two characteristics as being independent (as does modern OS theory):

The unit of resource ownership is usually referred to as a process or task. This Processes have:
a virtual address space which holds the process image.
protected access to processors, other processes, files, and I/O resources.
The unit of dispatching is usually referred to a thread or a lightweight process. Thus a thread:
Has an execution state (running, ready, etc.)
Saves thread context when not running
Has an execution stack and some per-thread static storage for local variables
Has access to the memory address space and resources of its process
all threads of a process share this when one thread alters a (non-private) memory item, all other threads (of the process) sees that a file open with one thread, is available to others
Benefits of Threads vs Processes
If implemented correctly then threads have some advantages of (multi) processes, They take:

Less time to create a new thread than a process, because the newly created thread uses the current process address space.
Less time to terminate a thread than a process.
Less time to switch between two threads within the same process, partly because the newly created thread uses the current process address space.
Less communication overheads -- communicating between the threads of one process is simple because the threads share everything: address space, in particular. So, data produced by one thread is immediately available to all the other threads.
Multithreading vs. Single threading
Just a we can multiple processes running on some systems we can have multiple threads running:
Single threading
-- when the OS does not recognize the concept of thread
Multithreading
-- when the OS supports multiple threads of execution within a single process
Figure node29fig:mthread28.1 shows a variety of models for threads and processes.
&160; mthread.gif>
 node29fig:mthread28.1 Threads and Processes Some example popular OSs and their thread support is:
MS-DOS
-- support a single user process and a single thread
UNIX
-- supports multiple user processes but only supports one thread per process
Solaris
-- supports multiple threads
Multithreading your code can have many benefits:
Improve application responsiveness -- Any program in which many activities are not dependent upon each other can be redesigned so that each activity is defined as a thread. For example, the user of a multithreaded GUI does not have to wait for one activity to complete before starting another.
Use multiprocessors more efficiently -- Typically, applications that express concurrency requirements with threads need not take into account the number of available processors. The performance of the application improves transparently with additional processors. Numerical algorithms and applications with a high degree of parallelism, such as matrix multiplications, can run much faster when implemented with threads on a multiprocessor.
Improve program structure -- Many programs are more efficiently structured as multiple independent or semi-independent units of execution instead of as a single, monolithic thread. Multithreaded programs can be more adaptive to variations in user demands than single threaded programs.
Use fewer system resources -- Programs that use two or more processes that access common data through shared memory are applying more than one thread of control. However, each process has a full address space and operating systems state. The cost of creating and maintaining this large amount of state information makes each process much more expensive than a thread in both time and space. In addition, the inherent separation between processes can require a major effort by the programmer to communicate between the threads in different processes, or to synchronize their actions.
Figure node29fig:sing_thr28.2 illustrates different process models and thread control in a single thread and multithreaded application.
&160; thread_stack.gif>
 node29fig:sing_thr28.2 Single and Multi- Thread Applicatiions Some Example applications of threads
:
Example : A file server on a LAN

It needs to handle several file requests over a short period
Hence more efficient to create (and destroy) a single thread for each request
Multiple threads can possibly be executing simultaneously on different processors
Example 2: Matrix Multiplication
Matrix Multilication essentially involves taking the rows of one matrix and multiplying and adding corresponding columns in a second matrix i.e:
&160; matrix.gif>
 node29fig:matrix28.3 Matrix Multiplication (3x3 example) Note that each element of the resultant matrix can be computed independently, that is to say by a different thread.
We will develop a C++ example program for matrix multiplication later (see Chapter ch:matrix).

Thread Levels
There are two broad categories of thread implementation:
User-Level Threads -- Thread Libraries.
Kernel-level Threads -- System Calls.
There are merits to both, in fact some OSs allow access to both levels (e.g. Solaris).
User-Level Threads (ULT)
In this level, the kernel is not aware of the existence of threads -- All thread management is done by the application by using a thread library. Thread switching does not require kernel mode privileges (no mode switch) and scheduling is application specific
Kernel activity for ULTs:

The kernel is not aware of thread activity but it is still managing process activity
When a thread makes a system call, the whole process will be blocked but for the thread library that thread is still in the running state
So thread states are independent of process states
Advantages and inconveniences of ULT
Advantages:

Thread switching does not involve the kernel -- no mode switching
Scheduling can be application specific -- choose the best algorithm.
ULTs can run on any OS -- Only needs a thread library
Disadvantages:

Most system calls are blocking and the kernel blocks processes -- So all threads within the process will be blocked
The kernel can only assign processes to processors -- Two threads within the same process cannot run simultaneously on two processors
Kernel-Level Threads (KLT)
In this level, All thread management is done by kernel No thread library but an API (system calls) to the kernel thread facility exists. The kernel maintains context information for the process and the threads, switching between threads requires the kernel Scheduling is performed on a thread basis.
Advantages and inconveniences of KLT
Advantages

the kernel can simultaneously schedule many threads of the same process on many processors blocking is done on a thread level
kernel routines can be multithreaded
Disadvantages:

thread switching within the same process involves the kernel, e.g if we have 2 mode switches per thread switch this results in a significant slow down.
Combined ULT/KLT Approaches
Idea is to combine the best of both approaches
Solaris is an example of an OS that combines both ULT and KLT (Figure node29fig:sol_thread28.4:
Thread creation done in the user space
Bulk of scheduling and synchronization of threads done in the user space
The programmer may adjust the number of KLTs
Process includes the user's address space, stack, and process control block
User-level threads (threads library) invisible to the OS are the interface for application parallelism
Kernel threads the unit that can be dispatched on a processor
Lightweight processes (LWP) each LWP supports one or more ULTs and maps to exactly one KLT
&160; solaris_thr.gif>
 node29fig:sol_thread28.4 Solaris Thread Implementation
Threads libraries
The interface to multithreading support is through a subroutine library, libpthread for POSIX threads, and libthread for Solaris threads. They both contain code for:
creating and destroying threads
passing messages and data between threads
scheduling thread execution
saving and restoring thread contexts
The POSIX Threads Library:libpthread, <pthread.h
Creating a () Thread
Use the function pthread_create() to add a new thread of control to the current process. It is prototyped by:
int pthread_create(pthread\_t *tid, const pthread\_attr\_t *tattr, void*(*start_routine)(void *), void *arg);

When an attribute object is not specified, it is NULL, and the thread is created with the following attributes:
It is unbounded
It is nondetached
It has a a stack and stack size
It inhetits the parent's priority
You can also create a attribute object with pthread_attr_init() function, and then use this attribute object to create a thread. See the Section node30sec:init_attr29.2
An example call of thread creation is:
include <pthread.h pthread_attr_t tattr; pthread_t tid; extern void *start_routine(void *arg); void *arg; int ret; /* behavior*/ ret = pthread_create(&tid, NULL, start_routine, arg); /* initialized with attributes */ ret = pthread_attr_init(&tattr); /* behavior specified*/ ret = pthread_create(&tid, &tattr, start_routine, arg);

The pthread_create() function is called with attr having the necessary state behavior. start_routine is the function with which the new thread begins execution. When start_routine returns, the thread exits with the exit status set to the value returned by start_routine.
When pthread_create is successful, the ID of the thread created is stored in the location referred to as tid.
Creating a thread using a NULL attribute argument has the same effect as using a attribute; both create a thread. When tattr is initialized, it acquires the behavior.
pthread_create() returns a zero and exits when it completes successfully. Any other returned value indicates that an error occurred.
Wait for Thread Termination
Use the pthread_join function to wait for a thread to terminate. It is prototyped by:
int pthread_join(thread_t tid, void **status);

An example use of this function is:
include <pthread.h pthread_t tid; int ret; int status; /* waiting to join thread "tidwith status */ ret = pthread_join(tid, &status); /* waiting to join thread "tidwithout status */ ret = pthread_join(tid, NULL);

The pthread_join() function blocks the calling thread until the specified thread terminates. The specified thread must be in the current process and must not be detached. When status is not NULL, it points to a location that is set to the exit status of the terminated thread when pthread_join() returns successfully. Multiple threads cannot wait for the same thread to terminate. If they try to, one thread returns successfully and the others fail with an error of ESRCH. After pthread_join() returns, any stack storage associated with the thread can be reclaimed by the application.
The pthread_join() routine takes two arguments, giving you some flexibility in its use. When you want the caller to wait until a specific thread terminates, supply that thread's ID as the first argument. If you are interested in the exit code of the defunct thread, supply the address of an area to receive it. Remember that pthread_join() works only for target threads that are nondetached. When there is no reason to synchronize with the termination of a particular thread, then that thread should be detached. Think of a detached thread as being the thread you use in most instances and reserve nondetached threads for only those situations that require them.
A Simple Threads Example
In this Simple Threads fragment below, one thread executes the procedure at the top, creating a helper thread that executes the procedure fetch, which involves a complicated database lookup and might take some time.
The main thread wants the results of the lookup but has other work to do in the meantime. So it does those other things and then waits for its helper to complete its job by executing pthread_join(). An argument, pbe, to the new thread is passed as a stack parameter. This can be done here because the main thread waits for the spun-off thread to terminate. In general, though, it is better to malloc() storage from the heap instead of passing an address to thread stack storage, which can disappear or be reassigned if the thread terminated.
The source for thread.c is as follows: void mainline (...) { struct phonebookentry *pbe; pthread_attr_t tattr; pthread_t helper; int status; pthread_create(&helper, NULL, fetch, &pbe); /* do something else for a while */ pthread_join(helper, &status); /* it's now safe to use result */ } void fetch(struct phonebookentry *arg) { struct phonebookentry *npbe; /* fetch value from a database */ npbe = search (prog_name) if (npbe != NULL) *arg = *npbe; pthread_exit(0); } struct phonebookentry { char name[64]; char phonenumber[32]; char flags[16]; }

Detaching a Thread
The function pthread_detach() is an alternative to pthread_join() to reclaim storage for a thread that is created with a detachstate attribute set to PTHREAD_CREATE_JOINABLE. It is prototyped by: int pthread\_detach(thread\_t tid);

A simple example of calling this fucntion to detatch a thread is given by: include <pthread.h pthread_t tid; int ret; /* detach thread tid */ ret = pthread_detach(tid);

The pthread_detach() function is used to indicate to the implementation that storage for the thread tid can be reclaimed when the thread terminates. If tid has not terminated, pthread_detach() does not cause it to terminate. The effect of multiple pthread_detach() calls on the same target thread is unspecified.
pthread_detach() returns a zero when it completes successfully. Any other returned value indicates that an error occurred. When any of the following conditions are detected, pthread_detach() fails and returns the an error value.
Create a Key for Thread-Specific Data
Single-threaded C programs have two basic classes of data: local data and global data. For multithreaded C programs a third class is added:thread-specific data (TSD). This is very much like global data, except that it is private to a thread.
Thread-specific data is maintained on a per-thread basis. TSD is the only way to define and refer to data that is private to a thread. Each thread-specific data item is associated with a key that is global to all threads in the process. Using the key, a thread can access a pointer (void *) that is maintained per-thread.
The function pthread_keycreate() is used to allocate a key that is used to identify thread-specific data in a process. The key is global to all threads in the process, and all threads initially have the value NULL associated with the key when it is created.
pthread_keycreate() is called once for each key before the key is used. There is no implicit synchronization. Once a key has been created, each thread can bind a value to the key. The values are specific to the thread and are maintained for each thread independently. The per-thread binding is deallocated when a thread terminates if the key was created with a destructor function. pthread_keycreate() is prototyped by:
int pthread_key_create(pthread_key_t *key, void (*destructor) (void *));

A simple example use of this function is:
include <pthread.h pthread_key_t key; int ret; /* key create without destructor */ ret = pthread_key_create(&key, NULL); /* key create with destructor */ ret = pthread_key_create(&key, destructor);

When pthread_keycreate() returns successfully, the allocated key is stored in the location pointed to by key. The caller must ensure that the storage and access to this key are properly synchronized. An optional destructor function, destructor, can be used to free stale storage. When a key has a non-NULL destructor function and the thread has a non-NULL value associated with that key, the destructor function is called with the current associated value when the thread exits. The order in which the destructor functions are called is unspecified.
pthread_keycreate() returns zero after completing successfully. Any other returned value indicates that an error occurred. When any of the following conditions occur, pthread_keycreate() fails and returns an error value.
Delete the Thread-Specific Data Key
The function pthread_keydelete() is used to destroy an existing thread-specific data key. Any memory associated with the key can be freed because the key has been invalidated and will return an error if ever referenced. (There is no comparable function in Solaris threads.)
pthread_keydelete() is prototyped by: int pthread_key_delete(pthread_key_t key);

A simple example use of this function is:
include <pthread.h pthread_key_t key; int ret; /* key previously created */ ret = pthread_key_delete(key);

Once a key has been deleted, any reference to it with the pthread_setspecific() or pthread_getspecific() call results in the EINVAL error.
It is the responsibility of the programmer to free any thread-specific resources before calling the delete function. This function does not invoke any of the destructors.
pthread_keydelete() returns zero after completing successfully. Any other returned value indicates that an error occurred. When the following condition occurs, pthread_keycreate() fails and returns the corresponding value.
Set the Thread-Specific Data Key
The function pthread_setspecific() is used to set the thread-specific binding to the specified thread-specific data key. It is prototyped by :
int pthread_setspecific(pthread_key_t key, const void *value);

A simple example use of this function is:
include <pthread.h pthread_key_t key; void *value; int ret; /* key previously created */ ret = pthread_setspecific(key, value);

pthread_setspecific() returns zero after completing successfully. Any other returned value indicates that an error occurred. When any of the following conditions occur, pthread_setspecific() fails and returns an error value.
Note: pthread_setspecific() does not free its storage. If a new binding is set, the existing binding must be freed; otherwise, a memory leak can occur.
Get the Thread-Specific Data Key
Use pthread_getspecific() to get the calling thread's binding for key, and store it in the location pointed to by value. This function is prototyped by:
int pthread_getspecific(pthread_key_t key);

A simple example use of this function is:
include <pthread.h pthread_key_t key; void *value; /* key previously created */ value = pthread_getspecific(key);

Global and Private Thread-Specific Data Example
Thread-Specific Data Global but Private
Consider the following code:
body() { ... while (write(fd, buffer, size) == -1) { if (errno != EINTR) { fprintf(mywindow, %s\n, strerror(errno)); exit(1); } } ... }

This code may be executed by any number of threads, but it has references to two global variables, errno and mywindow, that really should be references to items private to each thread.
Refere

Unix Shell - Using Quotes

Quotes

Provide control of collapsing of spaces and translation of variables
Try it: run three examples
No quotes (variables translated, spaces collapsed)
echo Home:   $HOME
  Home: /users/us/freddy
Double quotes (no collapsing)
echo "Home:   $HOME"
  Home:   /users/us/freddy
Single quotes (no translation or collapsing)
echo 'Home:   $HOME'
  Home:   $HOME
Try it: single quotes within double quotes
echo "Home directory '$HOME' is full..."
 
Page 75
 

Metacharacters

Characters with special meaning to shell
" ' ` $ * [ ] ?
; > < & ( ) \
Avoid special meaning with quoting
echo 'You have $20'
Backslash like single quotes
Applies only to next character
echo You have \$20
 
Page 76
 

Examples With Quotes

Bad command line:
grep dog.*cat file
Shell tries to expand dot.*cat as file name wildcard
Use quotes to avoid translation
grep 'dog.*cat' file
Single quotes OK in this case because we don't need variable translation

Page 77
 

More Examples With Quotes

Read name and search file for name
read name
grep "$name" dbase
Single quotes not OK because we need variable translation

Page 78
 

Searching for Metacharacters

Bad command line: search for dollar sign
grep "Gimme.*$20" file
Problem: shell translates variable $20
Solution: use single quotes
grep 'Gimme.*$20' file
 
Page 79

Unix Shell - More Miscellaneous

Temporary Files

Use unique names to avoid clashes
tempfile=$HOME/Weq_$$
command > $tempfile
$$ is PID of current shell
Avoids conflict with concurrent executions of script
Do not use /tmp!

Page 73
 

Wait Command

Wait for termination of background job
command &
pid=$!
(other processing)
wait $pid
Allows overlap of two or more operations
 
Photo 1 of 9