浅谈并发服务器----多线程并发---1

来源:互联网 发布:linux alias ll 编辑:程序博客网 时间:2024/06/07 02:57


                       

        前面说来利用多进程来实现并发服务器,然而这种方法也并非没有缺点,在Linux系统中,当一个进程需要另一个实体执行某事时,该进程就使用fork派生一个新的子进程,让子进程去进行处理。在这种并发服务器中可以看到,父进程负责接收链接请求,建立连接,然后派生子进程,由子进程处理与客户的交互。

虽然这种方式很多年来都使用的很好,但使用fork生成子进程存在一些问题,首先,fork占用大量的资源,内存映像要从父进程拷贝到子进程,所有描述符都在子进程中复制等。虽然但前采用写时拷贝(Copy-on-Write)技术,将真正的拷贝推迟到子进程有写操作时,但fork仍然需要占大量资源,其次,fork子进程后,需要进程键通信(IPC)在父子进程间传递信息。由于子进程从一开始就有父进程数据空间及所有的描述符的拷贝,所以fork之前的信息容易传递,但是从子进程返回信息给父进程就需要做很多工作。

而采用多线程来实现,有助于解决上面两个问题。

 

一,线程基础

     线程是进程内的独立执行实体和调度单元,又称为”轻量级”进程(Lightwight Process),创建线程比进程快10~100倍。一个进程内的所有线程共享相同的内存空间,全局变量等信息(这种机制又带来了同步问题),所以一个线程崩溃时,它会影响同一进程中的其他线程。除了共享全局变量外,他们还共享一下信息:进程治理,大多数数据,打开的文件描述符字,信号处理程序和信号处置,当前工作目录,用户ID和 组ID。

     但每个线程都有自己的私有信息:线程ID,寄存器集合(包括程序计数器和栈指针),栈(用于存放局部变量),error,信号掩码,优先级。

二,线程基础函数

    #include<pthread.h>

       Int Pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func(void *)), void *arg);

   如果新线程创建成功,参数tid返回新生成线程ID,一个进程中的每个线程都由一个线程ID标识,其类型为pthread_t。Attr指向线程属性的指针每个线程有很多属性名,包括优先级,起始栈大小,是否是守护线程等。通常将attr参数的值设为NULL,这时使用系统默认的属性。

     创建完一个新的线程后,需要说明它执行的函数。函数的地址由参数func指定。Func是一个函数指针,指向线程创建后要掉用的函数,这个被线程调用的函数也称为线程函数,该线程函数的调用参数是由arg指定的,arg是一个通用指针,用于往func()函数中传递参数,如果要传递多个参数时,必须将他们打包成一个结构,然后让arg指向该结构。

     如果线程调用成功返回0,出错则返回非0.

                

Pthread_create()函数的用法如下:thread.c

//线程的创建函数//程序名:createthread.c//编程时间:2012.7.21#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<pthread.h>//线程函数void *thread(void *arg){pthread_tnewthid;newthid = pthread_self();printf("this is a new thread, thread ID = %lu\n", newthid);return NULL;}int main(void){pthread_tthid;printf("main thread , ID is %lu\n",pthread_self());//打印主线程的IDif(pthread_create(&thid, NULL, (void *)thread, NULL) != 0)  {printf("thread ceatiion filed\n");exit(1);}sleep(1);exit(0);}
      linux下线程程序在编译时需要注意,gcc thread.c -o thread -pthread            注意到没在用gcc编译时要在后面加-pthread,这是链接线程静态库.

     线程中也有和进程的waitpid()函数功能类似的函数,等待一个线程终止,pthread_join()函数如下:

             #include<pthread,h>

            int pthread_join(pthread_t  tid, void **status);

参数tid指定要等待的ID。该函数必须指定尧等待的线程,不能等待任一个线程结束。要求等待的线程必须是等待进程的成员,并且不是分离的线程或守护线程。

几个线程不能同时等待一个线程完成(及多个线程调用pthread_join(),其指定同一个tid),如果其中一个成功调用pthread_join()函数,则其他线程将返回ESRCH

错误。如果等待的线程已经终止,则该函数立即返回。如果参数status指针非空,则指向终止线程的退出状态值。需要注意的是被等待的线程应该处于可join状态,

即非DETACHED状态。DETAVHED  状态是指对某个线程执行pthread_detach()后其所处的状态。处于DETACHED状态的线程无法由pthread_join()同步。

  在线程创建函数pthread_create有一个参数pthread_attr_t ,该类型是一个结构体类型。结构体如下:

            

typedef struct{    int                                   detachstate;    int                                   schedpolicy;    struct sched_param    schedpolicy;    int                                    inheritsched;    int                                   scope;    size_t                             guardsize;    int                                    stackaddr_set;    void *                               stackaddr;    size_t                               stacksize;}pthread_attr_t; 

各子段含义如下:(缺省<------->默认)

     1. detachstate:               表示新创键的线程是否与进程中其他的线程脱离同步。detachstate的缺省值为PATHREAD_CREATE_JOINABLE状态,这个属性也可以个用

                                             函数pthread_detach()来设置。如果将detachstate设置为PAHREAD_CREATE_DETACH(分离)状态,则detachstate不能载恢复到PATHREAD_CREATE_JOINABLE状态。(线程同步与异步的具体解释度娘或谷哥都行)

    2. schedpolicy:                表示新线程的调度策略,主要包括SCHED_OTHER(正常,非实时),SCHED_RR(实时,轮转法)和 SCHED_FIFO(实时,先进先出)3种,缺省为SCHED_OTHER,后两种调度算法仅对超级用户有用。

   3 . schedparam:               一个struct sched_param结构,其中一个sched_priority整型变量表示线程的运行优先级。这个参数仅当调度策略为实时(即SCHED_RR或SCHED_ FIFO)时才有效,缺省为0.

   4. inheritsched:                 有两种值可以选择,PTHEREAD_ECPLICIT_SCHED和PATHREAD_INHERIT_SCHED,前者表示新线程显示指定调度策略和调度参数(即attr中的值),而后者表示集成调用者线程的值。缺省为PTHREAD_EXPLICIT_SCHED.

   5. scope:                               表示进程间竞争CPU的范围,也就是说,线程优先级的有效范围。POSIX的标准中定义了两个值,PTHREAD_SCOPE_SYSTEM和PTHREAD_ SCOPE_PROCESS,前者biloxi系统中所有线程一起竞争CPU,后者表示仅与同进程的线程竞争CPU.

   6.guardsize:                    警戒堆栈的大小。

   7.stackaddr_set:              堆栈地址集。

   8.stackaddr:                     堆栈的地址。

   9.stacksize:                       堆栈大小。

 具体使用可在《Linux编程实战》中找到。。。。

           pthread_detach()函数将指定的线程变成分离的。

         pthread_detach()函数如下:

          #include<pthread.h>

               int pthread_detach(pthread_t tid);

        参数tid指定要设置为分离的线程ID。如果函数调用成功返回0,否则返回错误码。

 函数pthread_exit()用于终止当前线程,并返回状态值。如果当前线程是可联合的,则其退出状态将保留。

            pthread_exit()函数如下:

            #include<pthread.h>

                    void pthread_exit(void *status);

                  参数status指向函数的退出状态,这里的status不能指向一个局部变量,因为当前线程终止后其他所有的局部变量将

            被撤销。该函数没有返回值。

          还有两种方法可以使线程终止:

          (1)启动线程的函数ptread_create()的第3个参数返回。该返回值就是线程的终止状态。

           (2)如果进程的main()函数返回或者任何线程调用了exit()函数,进程将终止,线程将随之终止。

 


0 0