Unix 多线程

Unix   线程  
先来介绍线程的最基本操作  由浅入深
线程创建
 pthread_t   threadId;      线程的ID存储类型  类型为unsuigned long int
 int pthread_create(pthread_t,    线程的唯一标识ID   
                               const pthread_attr_t *,  优先级,调度策略,如果为NULL,采用默认属性
                              void*(*start_rtn)(void*),   必须设置  线程的运行体void* (*)(void*)
                              void* args);         线程运行体的参数    
    成功返回  0    失败 errno   同时设置 errno
main函数  也是一个线程  如果程序没有调用线程创建函数 那么程序只有一个线程就是main  称为主线程    当然线程也分父子关系,那么主线程就是创建所有线程的最高父线程,如果父线

程结束 ,那么它的所有子线程也将结束,如果不想让子线程没有正常结束父线程就结束了,那么可以通过一个函数让一个线程等待另一个线程结束,然后再向下执行

 int  pthread_join(pthread_t pid,  //要等待的线程ID
                            void **ptr)      //被等待的线程的返回值

当然此函数是一个堵塞函数 如果等待的线程一直不结束那么,调用pthread_join的线程也将一直等待下去,然后这个函数可以让我们的主线程不会在子线程退出前退出 但这个函数还有一个作用是很重要的 一个线程在默认的创建完成后它的状态是joinable的,这个状态的线程在正常结束后 如果父线程没有调用pthread_join来等待该子线程那么这个子线程就会变成像进程中的僵尸进程一样(结束了但资源没释放),pthread_join函数不仅仅是等待它也会回收这个线程的所占用的资源,但很多情况下我们并不希望主线程等待子线程的时候 堵塞在那,这时有另一个函数出现了
 pthread_detach(pthread_t )//线程ID
可以将线程状态修改为detached,这样这个线程就会在正常结束后自己回收资源,而且这个函数不会堵塞。

如果在线程的运行体中想获得当前线程的ID可以使用如下函数:
 pthread_t pthread_self();   //函数返回当前线程的ID
线程在运行中如想放弃CPU时间片可以使用 
  sched_yield();    //  在线程体中使用


现在再让我们来看看线程的结束
 1.首先就是线程体的正常运行完毕了,也就是线程正常结束
 2.在线程体中可以调用pthread_exit(void*返回值);属中断结束;
 3.在线程体中使用了return语句,结束函数体,也属中断结束;
 4.在线程体外可以使用pthread_cancel(pthread_t)向指定线程发送cancel信号
使用pthread_cancel终止线程的时候,还需要在线程代码中嵌入pthread_testcancel配合使用。
 这些都是结束线程的方法  都比较简单 这里就不再叙述了


多线程的程序中常见的问题就是多个线程同时使用一个资源 如同时去写一个文件,那么就会出现数据的混乱 也就是脏读,可出现这种情况后要怎么去处理呢?
   创建出一个互斥量
 pthread_mutex_t  t;       //互斥量
 pthread_mutex_init(pthread_mutex_t*,        //互斥量
   const pthread_mutexattr_t*)//互斥量的属性
   互斥量的使用
 在我们的多线程程序中,找出那些不希望多个线程同时运行的代码在代码的开头加上
 pthread_mutex_lock(pthread_mutex_t*)   //对互斥量的加锁
  不能多个线程同时运行的代码... 
   代码的结束要加上解锁
 pthread_mutex_unlock(pthread_mutex_t*)//对互斥量的解锁
   使用完毕后进行互斥量的销毁 
 pthread_mutex_destroy(pthread_mutex_t*)//销毁一个互斥量
下面pthread_mutex_lock简写为lock     pthread_mutex_unlock简写为unlock
这样在我们互斥量的lock和unlock之间的代码就只会有一个线程运行,每个线程都会先运行到lock这部分然后程序会检查互斥量的锁定状态,如果是锁定的那么此线程将进入休眠,直到互斥量不为锁定状态才会向下运行  这样我们就可以通过互斥量来保证程序不会出现资源抢占的问题  可这样那每个线程就都有个责任就是当一个线程锁定了资源以后,对应的就一定要对资源进行解锁,否则其它线程将一直等待下去,正常状态下是不会出现这种特殊情况的,但不知道大家有没有考虑过如果在锁定的代码中有线程中断结束的代码怎么办,例如:return  pthread_exit,一旦线程锁定了资源,可是这个线程却这样没有解锁的退出了,怎么办呢??
    幸好线程库中也提供了这样一对宏函数  来解决这个问题 
 pthread_cleanup_push(void (*)(void*),   // 指定的函数指针
                                       void *arg);          // 第1个参数的参数
 pthread_cleanup_pop(int );    // 0的时候不调用,1的时候调用push

指定的函数
 pthread_cleanup_push()/pthread_cleanup_pop()是以宏方式实现的,
这是pthread.h中的宏定义:
 #define pthread_cleanup_push(routine,arg) \ 
 { struct _pthread_cleanup_buffer _buffer; \ 
 _pthread_cleanup_push (&_buffer, (routine), (arg));
 #define pthread_cleanup_pop(execute) \ 
 _pthread_cleanup_pop (&_buffer, (execute)); }
可见,pthread_cleanup_push()带有一个"{",而pthread_cleanup_pop()带有一个"}",因此这两个函数必须成对出现 在我们使用互斥量将代码锁定以后,使用
 pthread_cleanup_push(pthread_mutex_unlock,arg);
 锁定的代码
 pthread_cleanup_pop(0);           
 这样如果在锁定的代码中出现了使线程结束的代码,那么在结束之前程序会调用push中指定的函数进行后续处理,我们可以在后续处理中对互斥量进行解锁,这样我们就可以避免程序进入死锁状态

现在在简单和介绍下线程间如果使用像进程中信号的技术
 我们知道在进程通信中有signal和kill的信号技术那么在线程中也同样提供了信号的发送和接收处理
 pthread_kill(pthread_t pid,      //线程ID
                    int signal);          //信号编号
 函数可以向指定的线程发送指定的信号 

在接收信号的线程中同样可以使用如下函数进行信号的接收处理
 sigwait(sigset_t sigs,        //信号的集合,接收到的信号如在其中则返回
             int siginfo);         //接收到的信号ID
 对于sigset_t集合的使用有如下几个步骤
 定义    sigset_t  sigs;
           sigemptyset(sigset_t*)   // 对指定信号集合初始化
           sigaddset(sigset_t*,int sig)  // 向信号集合中添加信号
           sigdelset(sigset_t*,int sig)  //从信号集合中删除信号
           sigismember(sigset_t*,int sig) //判断信号是否在集合中
           sigfillset(sigset_t*)        // 将集合中添满所有信号
这就是线程间信号的发送和接收处理了   

在线程中还有一项技术  是 条件量
 定义条件量pthread_cond_t
 初始化条件量pthread_cond_init(pthread_cond_t*, // 条件量  
                                                    pthread_condattr_t*)//结构体指定条件量属性
         此函数等待激发(由pthread_cond_signal/pthread_cond_broadcast)否则一直等待而且需要和互斥量一起使用防止多个线程同时调用此函数,如果没有条件量接收函数会自动先解锁互斥量然后进入休眠,当条件量到达时自动加锁互斥量并继续运行
 !! 必须在互斥量锁定的代码中使用
 等待条件量pthread_cond_wait(pthread_cond_t*,//条件量
                                                  pthread_mutex_t*)//互斥量
随机发送一个条件量,发送给当前正在等待的线程
                  发送条件量pthread_cond_signal(pthread_cond_t*);
会将所有等待条件量的都发送
                  群发条件量pthread_cond_broadcast(pthread_cond_t*);
条件量 比较类似信号   但相比信号又有一个优点  就是如果当前没有接收到,会自动让出CPU

个人理解    仅供参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值