⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 faq.html

📁 linux 下的线程库源码
💻 HTML
📖 第 1 页 / 共 3 页
字号:
it's the standard way of implementing cleanup handlers.<P><HR><P><H2><A NAME="E">E. Missing functions, wrong types, etc</A></H2><H4><A NAME="E.1">E.1: Where is <CODE>pthread_yield()</CODE> ? Howcomes LinuxThreads does not implement it?</A></H4>Because it's not part of the (final) POSIX 1003.1c standard.Several drafts of the standard contained <CODE>pthread_yield()</CODE>,but then the POSIX guys discovered it was redundant with<CODE>sched_yield()</CODE> and dropped it.  So, just use<CODE>sched_yield()</CODE> instead.<H4><A NAME="E.2">E.2: I've found some type errors in<code>&lt;pthread.h&gt;</code>.For instance, the second argument to <CODE>pthread_create()</CODE>should be a <CODE>pthread_attr_t</CODE>, not a<CODE>pthread_attr_t *</CODE>. Also, didn't you forget to declare <CODE>pthread_attr_default</CODE>?</A></H4>No, I didn't.  What you're describing is draft 4 of the POSIXstandard, which is used in OSF DCE threads.  LinuxThreads conforms to thefinal standard.  Even though the functions have the same names as indraft 4 and DCE, their calling conventions are slightly different.  Inparticular, attributes are passed by reference, not by value, anddefault attributes are denoted by the NULL pointer.  Since draft 4/DCEwill eventually disappear, you'd better port your program to use thestandard interface.<P><H4><A NAME="E.3">E.3: I'm porting an application from Solaris and Ihave to rename all thread functions from <code>thr_blah</code> to<CODE>pthread_blah</CODE>.  This is very annoying.  Why did you changeall the function names?</A></H4>POSIX did it.  The <code>thr_*</code> functions correspond to Solaristhreads, an older thread interface that you'll find only underSolaris.  The <CODE>pthread_*</CODE> functions correspond to POSIXthreads, an international standard available for many, many platforms.Even Solaris 2.5 and later support the POSIX threads interface.  So,do yourself a favor and rewrite your code to use POSIX threads: thisway, it will run unchanged under Linux, Solaris, and quite a lot ofother platforms.<P><H4><A NAME="E.4">E.4: How can I suspend and resume a thread fromanother thread? Solaris has the <CODE>thr_suspend()</CODE> and<CODE>thr_resume()</CODE> functions to do that; why don't you?</A></H4>The POSIX standard provides <B>no</B> mechanism by which a thread A cansuspend the execution of another thread B, without cooperation from B.The only way to implement a suspend/restart mechanism is to have Bcheck periodically some global variable for a suspend requestand then suspend itself on a condition variable, which another threadcan signal later to restart B.<P>Notice that <CODE>thr_suspend()</CODE> is inherently dangerous andprone to race conditions.  For one thing, there is no control on wherethe target thread stops: it can very well be stopped in the middle ofa critical section, while holding mutexes.  Also, there is noguarantee on when the target thread will actually stop.  For thesereasons, you'd be much better off using mutexes and conditionsinstead.  The only situations that really require the ability tosuspend a thread are debuggers and some kind of garbage collectors.<P>If you really must suspend a thread in LinuxThreads, you can send it a<CODE>SIGSTOP</CODE> signal with <CODE>pthread_kill</CODE>. Send<CODE>SIGCONT</CODE> for restarting it.Beware, this is specific to LinuxThreads and entirely non-portable.Indeed, a truly conforming POSIX threads implementation will stop allthreads when one thread receives the <CODE>SIGSTOP</CODE> signal!One day, LinuxThreads will implement that behavior, and thenon-portable hack with <CODE>SIGSTOP</CODE> won't work anymore.<P><H4><A NAME="E.5">E.5: LinuxThreads does not implement<CODE>pthread_attr_setstacksize()</CODE> nor<CODE>pthread_attr_setstackaddr()</CODE>.  Why? </A></H4>These two functions are part of optional components of the POSIXstandard, meaning that portable applications should test for the"feature test" macros <CODE>_POSIX_THREAD_ATTR_STACKSIZE</CODE> and<CODE>_POSIX_THREAD_ATTR_STACKADDR</CODE> (respectively) before using thesefunctions.<P><CODE>pthread_attr_setstacksize()</CODE> lets the programmer specifythe maximum stack size for a thread.  In LinuxThreads, stacks startsmall (4k) and grow on demand to a fairly large limit (2M), whichcannot be modified on a per-thread basis for architectural reasons.Hence there is really no need to specify any stack size yourself: thesystem does the right thing all by itself.  Besides, there is noportable way to estimate the stack requirements of a thread, sosetting the stack size is pretty useless anyway.<P><CODE>pthread_attr_setstackaddr()</CODE> is even more questionable: itlets users specify the stack location for a thread.  Again,LinuxThreads takes care of that for you.  Why you would ever need toset the stack address escapes me.<P><H4><A NAME="E.6">E.6: LinuxThreads does not support the<CODE>PTHREAD_SCOPE_PROCESS</CODE> value of the "contentionscope"attribute.  Why? </A></H4>With a "one-to-one" model, as in LinuxThreads (one kernel executioncontext per thread), there is only one scheduler for all processes andall threads on the system.  So, there is no way to obtain the behavior of<CODE>PTHREAD_SCOPE_PROCESS</CODE>.<H4><A NAME="E.7">E.7: LinuxThreads does not implement process-sharedmutexes, conditions, and semaphores. Why?</A></H4>This is another optional component of the POSIX standard.  Portableapplications should test <CODE>_POSIX_THREAD_PROCESS_SHARED</CODE>before using this facility.<P>The goal of this extension is to allow different processes (withdifferent address spaces) to synchronize through mutexes, conditionsor semaphores allocated in shared memory (either SVR4 shared memorysegments or <CODE>mmap()</CODE>ed files).<P>The reason why this does not work in LinuxThreads is that mutexes,conditions, and semaphores are not self-contained: their waitingqueues contain pointers to linked lists of thread descriptors, andthese pointers are meaningful only in one address space.<P>Matt Messier and I spent a significant amount of time trying to design asuitable mechanism for sharing waiting queues between processes.  Wecame up with several solutions that combined two of the followingthree desirable features, but none that combines all three:<UL><LI>allow sharing between processes having different UIDs<LI>supports cancellation<LI>supports <CODE>pthread_cond_timedwait</CODE></UL>We concluded that kernel support is required to share mutexes,conditions and semaphores between processes.  That's one place whereLinus Torvalds's intuition that "all we need in the kernel is<CODE>clone()</CODE>" fails.<P>Until suitable kernel support is available, you'd better usetraditional interprocess communications to synchronize differentprocesses: System V semaphores and message queues, or pipes, or sockets.<P><HR><P><H2><A NAME="F">F. C++ issues</A></H2><H4><A NAME="F.1">F.1: Are there C++ wrappers for LinuxThreads?</A></H4>Douglas Schmidt's ACE library contains, among a lot of otherthings, C++ wrappers for LinuxThreads and quite a number of otherthread libraries.  Check out<A HREF="http://www.cs.wustl.edu/~schmidt/ACE.html">http://www.cs.wustl.edu/~schmidt/ACE.html</A><P><H4><A NAME="F.2">F.2: I'm trying to use LinuxThreads from a C++program, and the compiler complains about the third argument to<CODE>pthread_create()</CODE> !</A></H4>You're probably trying to pass a class member function or someother C++ thing as third argument to <CODE>pthread_create()</CODE>.Recall that <CODE>pthread_create()</CODE> is a C function, and it mustbe passed a C function as third argument.<P><H4><A NAME="F.3">F.3: I'm trying to use LinuxThreads in conjunctionwith libg++, and I'm having all sorts of trouble.</A></H4>From what I understand, thread support in libg++ is completely broken,especially with respect to locking of iostreams.  H.J.Lu wrote:<BLOCKQUOTE>If you want to use thread, I can only suggest egcs and glibc. Youcan find egcs at<A HREF="http://www.cygnus.com/egcs">http://www.cygnus.com/egcs</A>.egcs has libsdtc++, which is MT safe under glibc 2. If you reallywant to use the libg++, I have a libg++ add-on for egcs.</BLOCKQUOTE><HR><P><H2><A NAME="G">G.  Debugging LinuxThreads programs</A></H2><H4><A NAME="G.1">G.1: Can I debug LinuxThreads program using gdb?</A></H4>Essentially, no.  gdb is basically not aware of the threads.  Itwill let you debug the main thread, and also inspect the global state,but you won't have any control over the other threads.  Worse, youcan't put any breakpoint anywhere in the code: if a thread other thanthe main thread hits the breakpoint, it will just crash!<P>For running gdb on the main thread, you need to instruct gdb to ignorethe signals used by LinuxThreads. Just do:<PRE>        handle SIGUSR1 nostop pass noprint        handle SIGUSR2 nostop pass noprint</PRE><H4><A NAME="G.2">G.2: What about attaching to a running thread usingthe <code>attach</code> command of gdb?</A></H4>For reasons I don't fully understand, this does not work.<P><H4><A NAME="G.3">G.3: But I know gdb supports threads on someplatforms! Why not on Linux?</A></H4>You're correct that gdb has some built-in support for threads, inparticular the IRIX "sprocs" model, which is a "one thread = oneprocess" model fairly close to LinuxThreads.  But gdb under IRIX usesioctls on <code>/proc</code> to control debugged processes, whileunder Linux it uses the traditional <CODE>ptrace()</CODE>. The supportfor threads is built in the <code>/proc</code> interface, but somework remains to be done to have it in the <CODE>ptrace()</CODE>interface.  In summary, it should not be impossible to get gdb to workwith LinuxThreads, but it's definitely not trivial.<H4><A NAME="G.4">G.4: OK, I'll do post-mortem debugging, then.  Butgdb cannot read core files generated by a multithreaded program!  Or,the core file is readable from gcc, but does not correspond to thethread that crashed!  What happens?</A></H4>Some versions of gdb do indeed have problems with post-mortemdebugging in general, but this is not specific to LinuxThreads.Recent Linux distributions seem to have corrected this problem,though.<P>Regarding the fact that the core file does not correspond to thethread that crashed, the reason is that the kernel will not dump corefor a process that shares its memory with other processes, such as theother threads of your program.  So, the thread that crashes silentlydisappears without generating a core file.  Then, all other threads ofyour program die on the same signal that killed the crashing thread.(This is required behavior according to the POSIX standard.)  The lastone that dies is no longer sharing its memory with anyone else, so thekernel generates a core file for that thread.  Unfortunately, that'snot the thread you are interested in.<H4><A NAME="G.5">G.5: How can I debug multithreaded programs, then?</A></H4>Assertions and <CODE>printf()</CODE> are your best friends.  Try to debugsequential parts in a single-threaded program first.  Then, put<CODE>printf()</CODE> statements all over the place to get execution traces.Also, check invariants often with the <CODE>assert()</CODE> macro.  In truth,there is no other effective way (save for a full formal proof of yourprogram) to track down concurrency bugs.  Debuggers are not reallyeffective for concurrency problems, because they disrupt programexecution too much.<P><HR><P><H2><A NAME="H">H. Compiling multithreaded code; errno madness</A></H2><H4><A NAME="H.1">H.1: You say all multithreaded code must be compiledwith <CODE>_REENTRANT</CODE> defined. What difference does it make?</A></H4>It affects include files in three ways:<UL><LI> The include files define prototypes for the reentrant variants ofsome of the standard library functions,e.g. <CODE>gethostbyname_r()</CODE> as a reentrant equivalent to<CODE>gethostbyname()</CODE>.<P><LI> If <CODE>_REENTRANT</CODE> is defined, some<code>&lt;stdio.h&gt;</code> functions are no longer defined as macros,e.g. <CODE>getc()</CODE> and <CODE>putc()</CODE>. In a multithreadedprogram, stdio functions require additional locking, which the macrosdon't perform, so we must call functions instead.<P><LI> More importantly, <code>&lt;errno.h&gt;</code> redefines errno when<CODE>_REENTRANT</CODE> is defined, so that errno refers to the thread-specific errno locationrather than the global errno variable.  This is achieved by thefollowing <code>#define</code> in <code>&lt;errno.h&gt;</code>:<PRE>        #define errno (*(__errno_location()))</PRE>which causes each reference to errno to call the<CODE>__errno_location()</CODE> function for obtaining the locationwhere error codes are stored.  libc provides a default definition of<CODE>__errno_location()</CODE> that always returns<code>&errno</code> (the address of the global errno variable). Thus,for programs not linked with LinuxThreads, defining<CODE>_REENTRANT</CODE> makes no difference w.r.t. errno processing.But LinuxThreads redefines <CODE>__errno_location()</CODE> to return alocation in the thread descriptor reserved for holding the currentvalue of errno for the calling thread.  Thus, each thread operates ona different errno location.</UL><P><H4><A NAME="H.2">H.2: Why is it so important that each thread has itsown errno variable? </A></H4>If all threads were to store error codes in the same, global errnovariable, then the value of errno after a system call or libraryfunction returns would be unpredictable:  between the time a systemcall stores its error code in the global errno and your code inspectserrno to see which error occurred, another thread might have storedanother error code in the same errno location. <P><H4><A NAME="H.3">H.3: What happens if I link LinuxThreads with codenot compiled with <CODE>-D_REENTRANT</CODE>?</A></H4>Lots of trouble.  If the code uses <CODE>getc()</CODE> or<CODE>putc()</CODE>, it will perform I/O without proper interlockingof the stdio buffers; this can cause lost output, duplicate output, orjust crash other stdio functions.  If the code consults errno, it willget back the wrong error code.  The following code fragment is atypical example:<PRE>        do {          r = read(fd, buf, n);          if (r == -1) {            if (errno == EINTR)   /* an error we can handle */              continue;            else {                /* other errors are fatal */              perror("read failed");              exit(100);            }          }        } while (...);</PRE>Assume this code is not compiled with <CODE>-D_REENTRANT</CODE>, andlinked with LinuxThreads.  At run-time, <CODE>read()</CODE> isinterrupted.  Since the C library was compiled with<CODE>-D_REENTRANT</CODE>, <CODE>read()</CODE> stores its error codein the location pointed to by <CODE>__errno_location()</CODE>, whichis the thread-local errno variable.  Then, the code above sees that

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -