LIINUX阻塞性肺炎打开是什么意思

liinux 编译参数 –D__KERNEL__ -DMODULE 是什么意思_百度知道
liinux 编译参数 –D__KERNEL__ -DMODULE 是什么意思
我有更好的答案
,不用反复该代码啦比如代码里有..:#ifdef __KERNEL__
&#47.#else
&#47, 那么你-D__KERNEL__就会执行1的部分;&#47。只不过在编译时指定参数这种做法比较方便.#endif之类的东西:#define __KERNEL__的效果一样啦; 2 。其实就和在代码中;&#47.; 1
Linux内核模块的编译KERNEL 是内核的意思MODULE是模块的意思想编译内核模块,需要使用这两个参数
为什么要加这两个参数,请大侠指点指点
其他类似问题
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁POSIX 多线程程序设计&
在多处理器共享内存的架构中(如:对称多处理系统),线程可以用于实现程序的并行性。历史上硬件销售商实现了各种私有版本的多线程库,使得软件开发者不得不关心它的移植性。对于系统,标准定义了一个语言多线程编程接口。依附于该标准的实现被称为或。&
该教程介绍了的概念、动机和设计思想。内容包含了主要的三大类函数:线程管理()、互斥量()和条件变量()。向刚开始学习的程序员提供了演示例程。&
适于:刚开始学习使用线程实现并行程序设计;对于并行程序设计有基本了解。不熟悉并行程序设计的可以参考。&
什么是线程?&
技术上,线程可以定义为:可以被操作系统调度的独立的指令流。但是这是什么意思呢?&
对于软件开发者,在主程序中运行的&函数过程&可以很好的描述线程的概念。&
进一步,想象下主程序()包含了许多函数,操作系统可以调度这些函数,使之同时或者(和)独立的执行。这就描述了&多线程&程序。&
怎样完成的呢?&
在理解线程之前,应先对进程()有所了解。进程被操作系统创建,需要相当多的&额外开销&。进程包含了程序的资源和执行状态信息。如下:&
进程,进程,用户和
文件描述符&
信号动作()&
进程间通信工具(如:消息队列,管道,信号量或共享内存)&
线程使用并存在于进程资源中,还可以被操作系统调用并独立地运行,这主要是因为线程仅仅复制必要的资源以使自己得以存在并执行。&
独立的控制流得以实现是因为线程维持着自己的:&
调度属性(如:策略或优先级)&
待定的和阻塞的信号集合()&
线程专用数据(:)&
因此,在环境下线程:&
存在于进程,使用进程资源&
拥有自己独立的控制流,只要父进程存在并且操作系统支持&
只复制必可以使得独立调度的必要资源&
可以和其他线程独立(或非独立的)地共享进程资源&
当父进程结束时结束,或者相关类似的&
是&轻型的&,因为大部分额外开销已经在进程创建时完成了&
因为在同一个进程中的线程共享资源:&
一个线程对系统资源(如关闭一个文件)的改变对所有其它线程是可以见的&
两个同样值的指针指向相同的数据&
读写同一个内存位置是可能的,因此需要成员显式地使用同步&
Pthreads 概述&
什么是 Pthreads?&
历史上,硬件销售商实现了私有版本的多线程库。这些实现在本质上各自不同,使得程序员难于开发可移植的应用程序。&
为了使用线程所提供的强大优点,需要一个标准的程序接口。对于系统,()标准制订了这一标准接口。依赖于该标准的实现就称为或者。现在多数硬件销售商也提供,附加于私有的。&
被定义为一些语言类型和函数调用,用头(包含)文件和线程库实现。这个库可以是其它库的一部分,如。&
Pthreads 概述&
为什么使用 Pthreads?&
使用的主要动机是提高潜在程序的性能。&
当与创建和管理进程的花费相比,线程可以使用操作系统较少的开销,管理线程需要较少的系统资源。&
例如,下表比较了函数和函数所用的时间。计时反应了个进程线程的创建,使用时间工具实现,单位是秒,没有优化标志。&
备注:不要期待系统和用户时间加起来就是真实时间,因为这些系统有多个同时工作。这些都是近似值。&
pthread_create()&
在同一个进程中的所有线程共享同样的地址空间。较于进程间的通信,在许多情况下线程间的通信效率比较高,且易于使用。&
较于没有使用线程的程序,使用线程的应用程序有潜在的性能增益和实际的优点:&
使用交叠工作:例如,一个程序可能有一个需要较长时间的操作,当一个线程等待系统调用完成时,可以被其它线程使用。&
优先实时调度:比较重要的任务可以被调度,替换或者中断较低优先级的任务。&
异步事件处理:频率和持续时间不确定的任务可以交错。例如,服务器可以同时为前一个请求传输数据和管理新请求。&
考虑在架构上使用的主要动机是获的最优的性能。特别的,如果一个程序使用在节点通信,使用可以使得节点数据传输得到显著提高。&
库经常用共享内存实现节点任务通信,这至少需要一次内存复制操作(进程到进程)。&
没有中间的内存复制,因为线程和一个进程共享同样的地址空间。没有数据传输。变成或的带宽(最坏情况),速度是相当的快。&
比较如下:&
MPI Shared Memory Bandwidth(GB/sec)&
Pthreads Worst CaseMemory-to-CPU Bandwidth (GB/sec)&
Pthreads 概述&
使用线程设计程序&
在现代多机器上,非常适于并行编程。可以用于并行程序设计的,也可以用于程序设计。&
并行程序要考虑许多,如下:&
用什么并行程序设计模型?&
加载平衡()&
同步和竞争条件&
程序复杂度&
程序员的努力花费时间&
包含这些主题超出本教程的范围,有兴趣的读者可以快速浏览下&&教程。&
大体上,为了使用的优点,必须将任务组织程离散的,独立的,可以并发执行的。例如,如果和可以互换,相互交叉和(或者)重叠,他们就可以线程化。&
拥有下述特性的程序可以使用:&
工作可以被多个任务同时执行,或者数据可以同时被多个任务操作。&
阻塞与潜在的长时间等待。&
在某些地方使用很多循环而其他地方没有。&
对异步事件必须响应。&
一些工作比其他的重要(优先级中断)。&
也可以用于串行程序,模拟并行执行。很好例子就是经典的浏览器,对于多数人,运行于单的桌面膝上机器,许多东西可以同时&显示&出来。&
使用线程编程的几种常见模型:&
管理者工作者():一个单线程,作为管理器将工作分配给其它线程(工作者),典型的,管理器处理所有输入和分配工作给其它任务。至少两种形式的模型比较常用:静态池和动态池。&
管道():任务可以被划分为一系列子操作,每一个被串行处理,但是不同的线程并发处理。汽车装配线可以很好的描述这个模型。&
和模型相似,但是主线程在创建了其它线程后,自己也参与工作。&
共享内存模型(Shared Memory Model):
所有线程可以访问全局,共享内存&
线程也有自己私有的数据&
程序员负责对全局共享数据的同步存取(保护)&
线程安全(Thread-safeness):
线程安全:简短的说,指程序可以同时执行多个线程却不会&破坏&共享数据或者产生&竞争&条件的能力。&
例如:假设你的程序创建了几个线程,每一个调用相同的库函数:&
这个库函数存取修改了一个全局结构或内存中的位置。&
当每个线程调用这个函数时,可能同时去修改这个全局结构活内存位置。&
如果函数没有使用同步机制去阻止数据破坏,这时,就不是线程安全的了。&
如果你不是确定外部库函数是线程安全的,自己负责所可能引发的问题。&
建议:小心使用库或者对象,当不能明确确定是否是线程安全的。若有疑虑,假设其不是线程安全的直到得以证明。可以通过不断地使用不确定的函数找出问题所在。&
Pthreads API&
在标准中定义。不像,该标准不是免费的,必须向购买。&
中的函数可以非正式的划分为三大类:&
线程管理() 第一类函数直接用于线程:创建(),分离(),连接()等等。包含了用于设置和查询线程属性(可连接,调度属性等)的函数。&
互斥量() 第二类函数是用于线程同步的,称为互斥量(),是的缩写。函数提供了创建,销毁,锁定和解锁互斥量的功能。同时还包括了一些用于设定或修改互斥量属性的函数。&
条件变量():第三类函数处理共享一个互斥量的线程间的通信,基于程序员指定的条件。这类函数包括指定的条件变量的创建,销毁,等待和受信()。设置查询条件变量属性的函数也包含其中。&
命名约定:线程库中的所有标识符都以开头&
Routine Prefix&
Functional Group&
线程本身和各种相关函数&
线程属性对象&
互斥量属性对象&
条件变量属性对象&
线程数据键()&
在的设计中充满了不透明对象的概念,基本调用可以创建或修改不透明对象。不透明的对象可以被一些属性函数调用修改。&
包含了多个函数。该教程仅限于一部分(对于刚开始学习的程序是非常有用的)。&
为了可移植性,使用库时,头文件必须在每个源文件中包含。&
现行标准仅定义了语言的使用。程序员可以嵌入函数调用使用,有些编译器(像)可能提供了。&
关于有些比较优秀的书籍。其中一些在该教程的参考一节列出。&
编译多线程程序&
下表列出了一些编译使用了库程序的命令:&
Compiler / Platform&
Compiler Command&
Description&
xlc_r &/& cc_r&
xlf_r -qnosavexlf90_r -qnosave&
INTELLinux&
icc -pthread&
icpc -pthread&
PathScaleLinux&
pathcc -pthread&
pathCC -pthread&
pgcc -lpthread&
pgCC -lpthread&
GNULinux, AIX&
gcc -pthread&
g++ -pthread&
线程管理(Thread Management)&
创建和结束线程&
(thread,attr,start_routine,arg) &
(status) &
最初,函数包含了一个缺省的线程。其它线程则需要程序员显式地创建。&
pthread_create创建一个新线程并使之运行起来。该函数可以在程序的任何地方调用。&
pthread_create参数:&
thread:返回一个不透明的,唯一的新线程标识符。&
attr:不透明的线程属性对象。可以指定一个线程属性对象,或者NULL为缺省值。&
start_routine:线程将会执行一次的函数。&
arg: 传递给单个参数,传递时必须转换成指向void的指针类型。没有参数传递时,可设置为NULL。&
一个进程可以创建的线程最大数量取决于系统实现。&
一旦创建,线程就称为,可以创建其它线程。线程之间没有指定的结构和依赖关系。&
:一个线程被创建后,怎么知道操作系统何时调度该线程使之运行?&
:除非使用了的调度机制,否则线程何时何地被执行取决于操作系统的实现。强壮的程序应该不依赖于线程执行的顺序。&
线程被创建时会带有默认的属性。其中的一些属性可以被程序员用线程属性对象来修改。&
pthread_attr_init和pthread_attr_destroy用于初始化/销毁先成属性对象。&
其它的一些函数用于查询和设置线程属性对象的指定属性。&
一些属性下面将会讨论。&
结束线程的方法有一下几种:&
线程从主线程(函数的初始线程)返回。&
线程调用了pthread_exit函数。&
其它线程使用pthread_cancel函数结束线程。&
调用或者函数,整个进程结束。&
pthread_exit用于显式退出线程。典型地,pthread_exit()函数在线程完成工作时,不在需要时候被调用,退出线程。&
如果在其他线程创建前用pthread_exit()退出了,其他线程将会继续执行。否则,他们会随着的结束而终止。&
程序员可以可选择的指定终止状态,当任何线程连接()该线程时,该状态就返回给连接()该线程的线程。&
清理:pthread_exit()函数并不会关闭文件,任何在线程中打开的文件将会一直处于打开状态,知道线程结束。&
讨论:对于正常退出,可以免于调用pthread_exit()。当然,除非你想返回一个返回值。然而,在main中,有一个问题,就是当main结束时,其它线程还没有被创建。如果此时没有显式的调用pthread_exit(),当main结束时,进程(和所有线程)都会终止。可以在main中调用pthread_exit(),此时尽管在main中已经没有可执行的代码了,进程和所有线程将保持存活状态,。&
例子: Pthread 创建和终止&
该例用pthread_create()创建了5个线程。每一个线程都会打印一条&Hello World&的消息,然后调用pthread_exit()终止线程。&
Example Code - Pthread Creation and Termination
#include &pthread.h&&
#include &stdio.h&&
#define NUM_THREADS&&&& 5&
void *PrintHello(void *threadid)&
&& tid = (int)&
&& printf("Hello World! It's me, thread #%d!\n", tid);&
&& pthread_exit(NULL);&
int main (int argc, char *argv[])&
&& pthread_t threads[NUM_THREADS];&
&& int rc,&
&& for(t=0; t&NUM_THREADS; t++){&
&&&&& printf("In main: creating thread %d\n", t);&
&&&&& rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);&
&&&&& if (rc){&
&&&&&&&& printf("ERROR; return code from pthread_create() is %d\n", rc);&
&&&&&&&& exit(-1);&
&& pthread_exit(NULL);&
向线程传递参数&
pthread_create()函数允许程序员想线程的start routine传递一个参数。当多个参数需要被传递时,可以通过定义一个结构体包含所有要传的参数,然后用pthread_create()传递一个指向改结构体的指针,来打破传递参数的个数的限制。&
所有参数都应该传引用传递并转化成()。&
:怎样安全地向一个新创建的线程传递数据?&
:确保所传递的数据是线程安全的(不能被其他线程修改)。下面三个例子演示了那个应该和那个不应该。&
Example 1 - Thread Argument Passing
下面的代码片段演示了如何向一个线程传递一个简单的整数。主线程为每一个线程使用一个唯一的数据结构,确保每个线程传递的参数是完整的。&
int *taskids[NUM_THREADS];&
for(t=0; t&NUM_THREADS; t++)&
&& taskids[t] = (int *) malloc(sizeof(int));&
&& *taskids[t] =&
&& printf("Creating thread %d\n", t);&
&& rc = pthread_create(&threads[t], NULL, PrintHello, &
&&&&&&& (void *) taskids[t]);&
Example 2 - Thread Argument Passing
例子展示了用结构体向线程设置传递参数。每个线程获得一个唯一的结构体实例。&
struct thread_data{&
&& int& thread_&
&& char *&
struct thread_data thread_data_array[NUM_THREADS];&
void *PrintHello(void *threadarg)&
&& struct thread_data *my_&
&& my_data = (struct thread_data *)&
&& taskid = my_data-&thread_&
&& sum = my_data-&&
&& hello_msg = my_data-&&
int main (int argc, char *argv[])&
&& thread_data_array[t].thread_id =&
&& thread_data_array[t].sum =&
&& thread_data_array[t].message = messages[t];&
&& rc = pthread_create(&threads[t], NULL, PrintHello, &
&&&&&&& (void *) &thread_data_array[t]);&
Example 3 - Thread Argument Passing &
例子演示了错误地传递参数。循环会在线程访问传递的参数前改变传递给线程的地址的内容。&
for(t=0; t&NUM_THREADS; t++) &
&& printf("Creating thread %d\n", t);&
&& rc = pthread_create(&threads[t], NULL, PrintHello, &
&&&&&&& (void *) &t);&
连接(Joining)和分离(Detaching)线程&
(threadid,status) &
(threadid,status) &
(attr,detachstate) &
(attr,detachstate) &
&连接&是一种在线程间完成同步的方法。例如:&
pthread_join()函数阻赛调用线程知道threadid所指定的线程终止。&
如果在目标线程中调用pthread_exit(),程序员可以在主线程中获得目标线程的终止状态。&
连接线程只能用pthread_join()连接一次。若多次调用就会发生逻辑错误。&
两种同步方法,互斥量()和条件变量(),稍后讨论。&
可连接(Joinable or Not)?
当一个线程被创建,它有一个属性定义了它是可连接的()还是分离的()。只有是可连接的线程才能被连接(),若果创建的线程是分离的,则不能连接。&
标准的最终草案指定了线程必须创建成可连接的。然而,并非所有实现都遵循此约定。&
使用pthread_create()的attr参数可以显式的创建可连接或分离的线程,典型四步如下:&
声明一个pthread_attr_t数据类型的线程属性变量&
用pthread_attr_init()初始化改属性变量&
用pthread_attr_setdetachstate()设置可分离状态属性&
完了后,用pthread_attr_destroy()释放属性所占用的库资源&
分离(Detaching):
pthread_detach()可以显式用于分离线程,尽管创建时是可连接的。&
没有与pthread_detach()功能相反的函数&
若线程需要连接,考虑创建时显式设置为可连接的。因为并非所有创建线程的实现都是将线程创建为可连接的。&
若事先知道线程从不需要连接,考虑创建线程时将其设置为可分离状态。一些系统资源可能需要释放。&
例子: Pthread Joining&
Example Code - Pthread Joining
这个例子演示了用函数去等待线程终止。因为有些实现并不是默认创建线程是可连接状态,例子中显式地将其创建为可连接的。
#include &pthread.h&&
#include &stdio.h&&
#define NUM_THREADS&&& 3&
void *BusyWork(void *null)&
&& double result=0.0;&
&& for (i=0; i&1000000; i++)&
&&&& result = result + (double)random();&
&& printf("result = %e\n",result);&
&& pthread_exit((void *) 0);&
int main (int argc, char *argv[])&
&& pthread_t thread[NUM_THREADS];&
&& pthread_attr_&
&& int rc,&
& &void *&
&& /* Initialize and set thread detached attribute */&
&& pthread_attr_init(&attr);&
&& pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);&
&& for(t=0; t&NUM_THREADS; t++)&
&&&&& printf("Creating thread %d\n", t);&
&&&&& rc = pthread_create(&thread[t], &attr, BusyWork, NULL); &
&&&&& if (rc)&
&&&&&&&& printf("ERROR; return code from pthread_create() &
&&&&&&&&&&&&&&& is %d\n", rc);&
&&&&&&&& exit(-1);&
&& /* Free attribute and wait for the other threads */&
&& pthread_attr_destroy(&attr);&
&& for(t=0; t&NUM_THREADS; t++)&
&&&&& rc = pthread_join(thread[t], &status);&
&&&&& if (rc)&
&&&&&&&& printf("ERROR; return code from pthread_join() &
&&&&&&&&&&&&&&& is %d\n", rc);&
&&&&&&&& exit(-1);&
&&&&& printf("Completed join with thread %d status= %ld\n",t, (long)status);&
&& pthread_exit(NULL);&
(attr, stacksize) &
(attr, stacksize) &
(attr, stackaddr) &
(attr, stackaddr) &
防止栈问题:
标准并没有指定线程栈的大小,依赖于实现并随实现变化。&
很容易超出默认的栈大小,常见结果:程序终止或者数据损坏。&
安全和可移植的程序应该不依赖于默认的栈限制,但是取而代之的是用pthread_attr_setstacksize分配足够的栈大小。&
pthread_attr_getstackaddr和pthread_attr_setstackaddr函数可以被程序用于将栈设置在指定的内存区域。&
在LC上的一些实际例子:
默认栈大小经常变化很大,最大值也变化很大,可能会依赖于每个节点的线程数目。&
NodeArchitecture&
Memory (GB)&
Default Size(bytes)&
例子: 栈管理&
Example Code - Stack Management
这个例子演示了如何去查询和设定线程栈大小。
#include &pthread.h&&
#include &stdio.h&&
#define NTHREADS 4&
#define N 1000&
#define MEGEXTRA 1000000&
pthread_attr_&
void *dowork(void *threadid)&
&& double A[N][N];&
&& int i,j,&
&& tid = (int)&
&& pthread_attr_getstacksize (&attr, &mystacksize);&
&& printf("Thread %d: stack size = %li bytes \n", tid, mystacksize);&
&& for (i=0; i&N; i++)&
&&&& for (j=0; j&N; j++)&
&&&&& A[i][j] = ((i*j)/3.452) + (N-i);&
&& pthread_exit(NULL);&
int main(int argc, char *argv[])&
&& pthread_t threads[NTHREADS];&
&& int rc,&
&& pthread_attr_init(&attr);&
&& pthread_attr_getstacksize (&attr, &stacksize);&
&& printf("Default stack size = %li\n", stacksize);&
&& stacksize = sizeof(double)*N*N+MEGEXTRA;&
&& printf("Amount of stack needed per thread = %li\n",stacksize);&
&& pthread_attr_setstacksize (&attr, stacksize);&
&& printf("Creating threads with stack size = %li bytes\n",stacksize);&
&& for(t=0; t&NTHREADS; t++){&
&&&&& rc = pthread_create(&threads[t], &attr, dowork, (void *)t);&
&&&&& if (rc){&
&&&&&&&& printf("ERROR; return code from pthread_create() is %d\n", rc);&
&&&&&&&& exit(-1);&
&& printf("Created %d threads.\n", t);&
&& pthread_exit(NULL);&
其他各种函数:&
(thread1,thread2) &
pthread_self返回调用该函数的线程的唯一,系统分配的线程ID。&
pthread_equal比较两个线程ID,若不同返回0,否则返回非0值。&
注意这两个函数中的线程对象是不透明的,不是轻易能检查的。因为线程是不透明的对象,所以语言的==操作符不能用于比较两个线程ID。&
(once_control, init_routine) &
pthread_once 在一个进程中仅执行一次init_routine。任何线程第一次调用该函数会执行给定的init_routine,不带参数,任何后续调用都没有效果。&
init_routine函数一般是初始化的程序&
once_control参数是一个同步结构体,需要在调用pthread_once前初始化。例如:&
pthread_once_t once_control = PTHREAD_ONCE_INIT;
互斥量(Mutex Variables)&
互斥量()是&&的缩写。互斥量是实现线程同步,和保护同时写共享数据的主要方法&
互斥量对共享数据的保护就像一把锁。在中,任何时候仅有一个线程可以锁定互斥量,因此,当多个线程尝试去锁定该互斥量时仅有一个会成功。直到锁定互斥量的线程解锁互斥量后,其他线程才可以去锁定互斥量。线程必须轮着访问受保护数据。&
互斥量可以防止&竞争&条件。下面的例子是一个银行事务处理时发生了竞争条件:&
上面的例子,当一个线程使用共享数据资源时,应该用一个互斥量去锁定&&。&
一个拥有互斥量的线程经常用于更新全局变量。确保了多个线程更新同样的变量以安全的方式运行,最终的结果和一个线程处理的结果是相同的。这个更新的变量属于一个&临界区()&。&
使用互斥量的典型顺序如下:&
创建和初始一个互斥量&
多个线程尝试去锁定该互斥量&
仅有一个线程可以成功锁定改互斥量&
锁定成功的线程做一些处理&
线程解锁该互斥量&
另外一个线程获得互斥量,重复上述过程&
最后销毁互斥量&
当多个线程竞争同一个互斥量时,失败的线程会阻塞在调用处。可以用&&替换&&,则失败时不会阻塞。&
当保护共享数据时,程序员有责任去确认是否需要使用互斥量。如,若四个线程会更新同样的数据,但仅有一个线程用了互斥量,则数据可能会损坏。&
互斥量(Mutex Variables)&
创建和销毁互斥量&
(mutex,attr) &
互斥量必须用类型类型声明,在使用前必须初始化,这里有两种方法可以初始化互斥量:&
声明时静态地,如:pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
动态地用函数,这种方法允许设定互斥量的属性对象。&
互斥量初始化后是解锁的。&
对象用于设置互斥量对象的属性,使用时必须声明为类型,默认值可以是。标准定义了三种可选的互斥量属性:&
协议():指定了协议用于阻止互斥量的优先级改变&
优先级上限():指定互斥量的优先级上限&
进程共享():指定进程共享互斥量&
注意所有实现都提供了这三个可先的互斥量属性。&
pthread_mutexattr_init()和pthread_mutexattr_destroy()函数分别用于创建和销毁互斥量属性对象。&
pthread_mutex_destroy()应该用于释放不需要再使用的互斥量对象。&
互斥量(Mutex Variables)&
锁定和解锁互斥量&
线程用pthread_mutex_lock()函数去锁定指定的mutex变量,若该mutex已经被另外一个线程锁定了,该调用将会阻塞线程直到mutex被解锁。&
pthread_mutex_trylock()
pthread_mutex_trylock()尝试着去锁定一个互斥量,然而,若互斥量已被锁定,程序会立刻返回并返回一个忙错误值。该函数在优先级改变情况下阻止死锁是非常有用的。&
线程可以用pthread_mutex_unlock()解锁自己占用的互斥量。在一个线程完成对保护数据的使用,而其它线程要获得互斥量在保护数据上工作时,可以调用该函数。若有一下情形则会发生错误:&
互斥量已经被解锁&
互斥量被另一个线程占用&
互斥量并没有多么&神奇&的,实际上,它们就是参与的线程的&君子约定&。写代码时要确信正确地锁定,解锁互斥量。下面演示了一种逻辑错误:&
&&&&&&&&&&&&&&&& &&&&Thread 1&&&& Thread 2&&&& Thread 3&
&&&&&&&&&&&&&&&& &&&&Lock&&&&&&&& Lock&&&&&&&& &
&&&&&&&&&&&&&&&& &&&&A = 2&&&&&&& A = A+1&&&&& A = A*B&
&&&&&&&&&&&&&&&& &&&&Unlock&&&&&& Unlock&&& &
:有多个线程等待同一个锁定的互斥量,当互斥量被解锁后,那个线程会第一个锁定互斥量?&
:除非线程使用了优先级调度机制,否则,线程会被系统调度器去分配,那个线程会第一个锁定互斥量是随机的。&
例子:使用互斥量&
Example Code - Using Mutexes
例程演示了线程使用互斥量处理一个点积()计算。主数据通过一个可全局访问的数据结构被所有线程使用,每个线程处理数据的不同部分,主线程等待其他线程完成计算并输出结果。&
#include &pthread.h&&
#include &stdio.h&&
#include &malloc.h&&
The following structure contains the necessary information& &
to allow the function "dotprod" to access its input data and &
place its output into the structure.& &
typedef struct &
&& double&&&&& *a;&
&& double&&&&& *b;&
&& double&&&&
&& int&&&&
&} DOTDATA;&
/* Define globally accessible variables and a mutex */&
#define NUMTHRDS 4&
#define VECLEN 100&
&& DOTDATA &
&& pthread_t callThd[NUMTHRDS];&
&& pthread_mutex_&
The function dotprod is activated when the thread is created.&
All input to this routine is obtained from a structure &
of type DOTDATA and all output from this function is written into&
this structure. The benefit of this approach is apparent for the &
multi-threaded program: when a thread is created we pass a single&
argument to the activated function - typically this argument&
is a thread number. All& the other information required by the &
function is accessed from the globally accessible structure. &
void *dotprod(void *arg)&
&& /* Define and use local variables for convenience */&
&& int i, start, end, offset,&
&& double mysum, *x, *y;&
&& offset = (int)&
&& len = dotstr.&
&& start = offset*&
&& end&& = start +&
&& x = dotstr.a;&
&& y = dotstr.b;&
&& Perform the dot product and assign result&
&& to the appropriate variable in the structure. &
&& mysum = 0;&
&& for (i= i& i++) &
&&&&& mysum += (x[i] * y[i]);&
&& Lock a mutex prior to updating the value in the shared&
&& structure, and unlock it upon updating.&
&& pthread_mutex_lock (&mutexsum);&
&& dotstr.sum +=&
&& pthread_mutex_unlock (&mutexsum);&
&& pthread_exit((void*) 0);&
The main program creates threads which do all the work and then &
print out result upon completion. Before creating the threads,&
the input data is created. Since all threads update a shared structure, &
we need a mutex for mutual exclusion. The main thread needs to wait for&
all threads to complete, it waits for each one of the threads. We specify&
a thread attribute value that allow the main thread to join with the&
threads it creates. Note also that we free up handles when they are&
no longer needed.&
int main (int argc, char *argv[])&
&& double *a, *b;&
&& void *&
&& pthread_attr_&
&& /* Assign storage and initialize values */&
&& a = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));&
&& b = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));&
&& for (i=0; i&VECLEN*NUMTHRDS; i++)&
&&&& a[i]=1.0;&
&&&& b[i]=a[i];&
&& dotstr.veclen = VECLEN; &
&& dotstr.a = &
&& dotstr.b = &
&& dotstr.sum=0;&
&& pthread_mutex_init(&mutexsum, NULL);&
&&&&&&&& &
&& /* Create threads to perform the dotproduct& */&
&& pthread_attr_init(&attr);&
&& pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);&
&&&&&&& for(i=0; i&NUMTHRDS; i++)&
&&&&&&& {&
&&&&&&& /* &
&&&&&&& Each thread works on a different set of data.&
&&&&&&& The offset is specified by 'i'. The size of&
&&&&&&& the data for each thread is indicated by VECLEN.&
&&&&&&& */&
&&&&&&& pthread_create( &callThd[i], &attr, dotprod, (void *)i);&
&&&&&&& }&
&&&&&&& pthread_attr_destroy(&attr);&
&&&&&&& /* Wait on the other threads */&
&&&&&&& for(i=0; i&NUMTHRDS; i++)&
&&&&&& &{&
&&&&&&& & pthread_join( callThd[i], &status);&
&&&&&&& }&
&& /* After joining, print out the results and cleanup */&
&& printf ("Sum =& %f \n", dotstr.sum);&
&& free (a);&
&& free (b);&
&& pthread_mutex_destroy(&mutexsum);&
&& pthread_exit(NULL);&
条件变量(Condition Variables)&
条件变量提供了另一种同步的方式。互斥量通过控制对数据的访问实现了同步,而条件变量允许根据实际的数据值来实现同步。&
没有条件变量,程序员就必须使用线程去轮询(可能在临界区),查看条件是否满足。这样比较消耗资源,因为线程连续繁忙工作。条件变量是一种可以实现这种轮询的方式。&
条件变量往往和互斥一起使用&
使用条件变量的代表性顺序如下:&
主线程(Main Thread)
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 声明和初始化需要同步的全局数据变量(如&&)&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 生命和初始化一个条件变量对象&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 声明和初始化一个相关的互斥量&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 创建工作线程和
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 工作,一直到一定的条件满足(如&&等于一个指定的值)&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 锁定相关互斥量并检查全局变量的值&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 调用pthread_cond_wait()阻塞等待Thread-B的信号。注意pthread_cond_wait()能够自动地并且原子地解锁相关的互斥量,以至于它可以被Thread-B使用。&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 当收到信号,唤醒线程,互斥量被自动,原子地锁定。&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 显式解锁互斥量&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 继续&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 工作&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 锁定相关互斥量&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 改变所等待的全局变量&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 检查全局变量的值,若达到需要的条件,像发信号。&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 解锁互斥量&
o&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 继续&
Main Thread
条件变量(Condition Variables)&
创建和销毁条件变量&
(condition,attr) &
(condition) &
条件变量必须声明为pthread_cond_t类型,必须在使用前初始化。有两种方式可以初始条件变量:&
声明时静态地。如:pthread_cond_t myconvar = PTHREAD_COND_INITIALIZER;
用pthread_cond_init()函数动态地。创建的条件变量ID通过condition参数返回给调用线程。该方式允许设置条件变量对象的属性,attr。&
可选的对象用于设定条件变量的属性。仅有一个属性被定义:线程共享(),可以使条件变量被其它进程中的线程看到。若要使用属性对象,必须定义为pthread_condattr_t类型(可以指定为NULL设为默认)。&
注意所有实现都提供了线程共享属性。&
pthread_condattr_init()和pthread_condattr_destroy()用于创建和销毁条件变量属性对象。&
条件变量不需要再使用时,应用pthread_cond_destroy()释放条件变量。&
条件变量(Condition Variables)&
在条件变量上等待(Waiting)和发送信号(Signaling)&
(condition,mutex) &
(condition) &
(condition) &
pthread_cond_wait()阻塞调用线程直到指定的条件受信(signaled)。该函数应该在互斥量锁定时调用,当在等待时会自动解锁互斥量。在信号被发送,线程被激活后,互斥量会自动被锁定,当线程结束时,由程序员负责解锁互斥量。&
pthread_cond_signal()函数用于向其他等待在条件变量上的线程发送信号(激活其它线程)。应该在互斥量被锁定后调用。&
若不止一个线程阻塞在条件变量上,则应用pthread_cond_broadcast()向其它所以线程发生信号。&
在调用pthread_cond_wait()前调用pthread_cond_signal()会发生逻辑错误。&
使用这些函数时适当的锁定和解锁相关的互斥量是非常重要的。如:&
调用pthread_cond_wait()前锁定互斥量失败可能导致线程不会阻塞。&
调用pthread_cond_signal()后解锁互斥量失败可能会不允许相应的pthread_cond_wait()函数结束(保存阻塞)。&
例子:使用条件变量&
Example Code - Using Condition Variables
例子演示了使用条件变量的几个函数。主程序创建了三个线程,两个线程工作,根系&&变量。第三个线程等待变量值达到指定的值。&
#include &pthread.h&&
#include &stdio.h&&
#define NUM_THREADS& 3&
#define TCOUNT 10&
#define COUNT_LIMIT 12&
int&&&& count = 0;&
int&&&& thread_ids[3] = {0,1,2};&
pthread_mutex_t count_&
pthread_cond_t count_threshold_&
void *inc_count(void *idp) &
& int j,i;&
& double result=0.0;&
& int *my_id =&
& for (i=0; i&TCOUNT; i++) {&
&&& pthread_mutex_lock(&count_mutex);&
&&& count++;&
&&& Check the value of count and signal waiting thread when condition is&
&&& reached.& Note that this occurs while mutex is locked. &
&&& if (count == COUNT_LIMIT) {&
&&&&& pthread_cond_signal(&count_threshold_cv);&
&&&&& printf("inc_count(): thread %d, count = %d& Threshold reached.\n", &
&&&&&&&&&&&& *my_id, count);&
&&& printf("inc_count(): thread %d, count = %d, unlocking mutex\n", &
&&&&&&& && *my_id, count);&
&&& pthread_mutex_unlock(&count_mutex);&
&&& /* Do some work so threads can alternate on mutex lock */&
&&& for (j=0; j&1000; j++)&
&&&&& result = result + (double)random();&
& pthread_exit(NULL);&
void *watch_count(void *idp) &
& int *my_id =&
& printf("Starting watch_count(): thread %d\n", *my_id);&
& Lock mutex and wait for signal.& Note that the pthread_cond_wait &
& routine will automatically and atomically unlock mutex while it waits. &
& Also, note that if COUNT_LIMIT is reached before this routine is run by&
& the waiting thread, the loop will be skipped to prevent pthread_cond_wait&
& from never returning. &
& pthread_mutex_lock(&count_mutex);&
& if (count&COUNT_LIMIT) {&
&&& pthread_cond_wait(&count_threshold_cv, &count_mutex);&
&&& printf("watch_count(): thread %d Condition signal &
&&&&&&&&&& received.\n", *my_id);&
& pthread_mutex_unlock(&count_mutex);&
& pthread_exit(NULL);&
int main (int argc, char *argv[])&
& pthread_t threads[3];&
& pthread_attr_&
& /* Initialize mutex and condition variable objects */&
& pthread_mutex_init(&count_mutex, NULL);&
& pthread_cond_init (&count_threshold_cv, NULL);&
& /* For portability, explicitly create threads in a joinable state */&
& pthread_attr_init(&attr);&
& pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);&
& pthread_create(&threads[0], &attr, inc_count, (void *)&thread_ids[0]);&
& pthread_create(&threads[1], &attr, inc_count, (void *)&thread_ids[1]);&
& pthread_create(&threads[2], &attr, watch_count, (void *)&thread_ids[2]);&
& /* Wait for all threads to complete */&
& for (i=0; i&NUM_THREADS; i++) {&
&&& pthread_join(threads[i], NULL);&
& printf ("Main(): Waited on %d& threads. Done.\n", NUM_THREADS);&
& /* Clean up and exit */&
& pthread_attr_destroy(&attr);&
& pthread_mutex_destroy(&count_mutex);&
& pthread_cond_destroy(&count_threshold_cv);&
& pthread_exit(NULL);&
没有覆盖的主题&
的几个特性在该教程中并没有包含。把它们列在下面:&
线程如何调度的实现往往是不同的,在大多数情况下,默认的机制是可以胜任的。&
 提供了显式设定线程调度策略和优先级的函数,它们可以重载默认机制。&
不需要实现去支持这些特性&
:线程数据()&
互斥量的属性和优先级管理&
跨进程的条件变量共享&
取消线程()&
多线程和信号()
Pthread 库API参考&
Pthread Functions&
Pthread Attribute Functions&
Mutex Functions&
Mutex Attribute Functions&
Condition Variable Functions&
Condition Variable Attribute Functions&
&三天时间,终于在工作期间,抽空把上一篇POSIX threads programing翻译完了。由于水平有限,翻译质量差强人意,若有不合理或错误之处,请您之处,在此深表感谢!有疑问点此查看原文。在参考部分提及的几本关于Pthreads库的大作及该文章原文和译文可在下面的连接下载:
本篇及其英文原文:&
多线程编程指南:&
Programing with POSIX thread(强烈推荐):
Pthread Primer(强烈推荐):
author: david()code page:
阅读(...) 评论()}

我要回帖

更多关于 阻塞性肺炎 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信