
一、Linux环境下的线程
相对于其他操作系统,Linux系统内核只提供了轻量级进程的支持,并未实现线程模型。Linux是一种“多进程单线程”的操作系统,Linux本身只有进程的概念,而其所谓的“线程”本质上在内核里仍然是进程。
一个进程内存的所有线程共享进程的资源(代码区、全局区、堆、文件目录……)。多线程资源控制,由于线程之间共享进程中的资源,所以同一进程中的多个线程的通讯的重心之一是对共享的资源进行控制,例如当多个线程同时使用进程某个资源时,有可能需要采用互斥/同步等手段保证资源被正确操作,在采用互斥/同步手段时候,需要避免产生死锁的情况。5) 地址空间和其他资源(如打开的文件):进程的地址空间之间互相独立,同一进程的各线程间共享进程的资源,某进程内的线程对于其他进程不可见。
linux支持内核级的线程,但它将线程定义为进程的另一个“执行上下文”多线程编程,从而简化了进程/线程之间的关系和调度程序的设计,它的线程库提供了和posix兼容的线程同步机制。而 m:n 模型下,多个用户线程对应于内核中的多个内核线程,用户线程调度仅限于在本进程范围内进行,而对应的内核线程则交由内核进行调度。其实也有各自的真实pid,但由结构隐藏了,对外的pid为主进程的pid5)线程对操作系统来说就是进程,因此对信号的处理是以进程为单位分发的6)线程总数受限于系统进程数7)系统管理线程的瓶颈:所有线程由管理线程管理8)线程之间的调度是由内核调度器来处理的9)由于计算线程本地数据的方法是基于堆栈地址的位置。
其实也有各自的真实pid,但由结构隐藏了,对比较 solaris posix 定义 usync_processpthread_process_shared 用于同步该进程和其他进程中的线程 usync_process_robust 无posix 等效项 用于在进程间可靠地同步线程 usync_thread pthread_process_private用于仅同步该进程中的线程。
二、Linux环境下的多线程编译支持
按照POSIX 1003.1c 标准编写的程序与Linuxthread 库相链接即可支持Linux平台上的多线程,在程序中需包含头文件pthread. h,在编译链接时使用命令:
gcc -D -REENTRANT -lpthread xxx. c
其中-REENTRANT宏使得相关库函数(如stdio.h、errno.h中函数) 是可重入的、线程安全的(thread-safe),-lpthread则意味着链接库目录下的libpthread.a或libpthread.so文件。

在一个多线程程序里,默认情况下,只有一个errno变量供所有的线程共享。在一个线程准备获取刚才的错误代码时,该变量很容易被另一个线程中的函数调用所改变。类似的问题还存在于fputs之类的函数中,这些函数通常用一个单独的全局性区域来缓存输出数据。
为解决这个问题,需要使用可重入的例程。可重入代码可以被多次调用而仍然工作正常。编写的多线程程序,通过定义宏_REENTRANT来告诉编译器我们需要可重入功能,这个宏的定义必须出现于程序中的任何#include语句之前。
_REENTRANT为我们做三件事情,并且做的非常优雅:
(1)它会对部分函数重新定义它们的可安全重入的版本,这些函数名字一般不会发生改变,只是会在函数名后面添加_r字符串,如函数名gethostbyname变成gethostbyname_r。
(2)stdio.h中原来以宏的形式实现的一些函数将变成可安全重入函数。
f inline '函数表达式','变量1','变量2',... y f 实参列表 实参列表应与定义时的变量顺序保持一致 例: 方式三:内联函数和匿名函数 内联函数 调用方式 f inline 'x^2+y','x','y' y f 2,3 根据实际情况,定义函数时可能需要使用数组运算 例: 方式三:内联函数和匿名函数 匿名函数 + 函数句柄 f @ 变量列表 表达式 y f 实参列表 调用方式 f @ x,y x^2 + y。先说说用getmodulehandle函数获取.此方法需要用createremotethread函数在远程进程中创建线程,让该线程调用kernel32.dll中的getmodulehandle函数.但是只这样还不行.因为getmodulehandle函数需要以dll模块文件名做参数.既然是远程线程调用getmodulehandle函数.还需要先把dll模块文件名写入目标进程的地址空间中.最后用createremotethread函数创建线程执行getmodulehandle函数来获取dll句柄。thread32next()遍历系统中所有线程.将遍历到的线程保存到threadentry32结构,然后判断结构中的th32ownerprocessid成员是否与目标进程id是否相等从而判断该线程是否为目标进程的.然后用函数openthread()打开该线程.但是openthread函数在vc6中未被定义.该函数存在于kernel32.dll中.在使用时需要自己定义:第三个参数指定要打开的线程的id(从threadentry32结构获取)。
三、Linux环境下的多线程函数
3.1 线程创建
在进程被创建时多线程编程,系统会为其创建一个主线程,而要在进程中创建新的线程,则可以调用pthread_create函数:

#include <pthread.h> int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
参数说明:
返回值:
调用如果成功,则返回值是0;如果失败则返回错误代码。
答:“监视进线程创建”将icesword运行期间的进线程创建调用记录在循环缓冲里,“监视进程终止”记录1个进程被其它进程terminate的情况。“监视进线程创建”将icesword运行期间的进线程创建调用记录在循环缓冲里,“监视进程终止”记录一个进程被其它进程terminate的情况。在linux系统中,posix线程可以“看做”为一种轻量级的进程,pthread_create创建线程和fork创建进程都是在内核中调用__clone函数创建的,只不过创建线程或进程的时候选项不同,比如是否共享虚拟地址空间、文件描述符等。
pthread_self (void);
3.2 线程退出
线程的退出方式有三种:
(1)执行完成后隐式退出;

(2)由线程本身显示调用pthread_exit 函数退出;
pthread_exit (void * retval);
(3)被其他线程用pthread_cance函数终止:
pthread_cancel (pthread_t thread);
如果一个线程要等待另一个线程的终止,可以使用pthread_join函数,该函数的作用是调用pthread_join的线程将被挂起直到线程ID为参数thread的线程终止:
pthread_join (pthread_t thread, void** threadreturn);
3.3 简单的多线程示例
一个简单的Linux多线程示例如下:



#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> void *thread_function(void *arg); char message[] = "Hello World"; int main() { int res; pthread_t a_thread; void *thread_result; res = pthread_create(&a_thread, NULL, thread_function, (void *)message); if (res != 0) { perror("Thread creation failed!"); exit(EXIT_FAILURE); } printf("Waiting for thread to finish.../n"); res = pthread_join(a_thread, &thread_result); if (res != 0) { perror("Thread join failed!/n"); exit(EXIT_FAILURE); } printf("Thread joined, it returned %s/n", (char *)thread_result); printf("Message is now %s/n", message); exit(EXIT_FAILURE); } void *thread_function(void *arg) { printf("thread_function is running. Argument was %s/n", (char *)arg); sleep(3); strcpy(message, "Bye!"); pthread_exit("Thank you for your CPU time!"); }
View Code
编译语句如下:
gcc -D_REENTRANT thread1.c -o thread1 –lpthread
输出结果是:
$./thread1[输出]: thread_function is running. Argument was Hello World Waiting for thread to finish... Thread joined, it returned Thank you for your CPU time! Message is now Bye!
在这个例子中,pthread_exit(void *retval)本身返回的就是指向某个对象的指针,因此,pthread_join(pthread_t th, void **thread_return);中的thread_return是二级指针,指向线程返回值的指针。可以看到,我们创建的新线程修改的数组message的值,而原先的线程也可以访问该数组。如果我们调用的是fork而不是pthread_create,就不会有这样的效果了。因为fork创建子进程之后,子进程会拷贝父进程,两者分离,相互不干扰,而线程之间则是共享进程的相关资源。
小结:
本文主要讲了Linux环境下的多线程基本概念,包括多线程的实现方式、函数接口、功能特性等。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-106823-1.html
中国没有像样的民族工业