15-多线程互斥和同步

注意:与进程区分开来。
线程同步:多个线程按照先后顺序执行,就像是排了队列一样,一个一个来;
线程互斥:多个线程对同个资源操作,为了保证被访问资源的原子性(一次只能有一个线程使用资源),所以要互斥。

一、什么是多线程

 *  线程就是“轻量级”的进程。
 *  线程与创建它的进程共享代码段,数据段。
 *  线程拥有自己独立的栈

二、多线程函数

(转)所谓最简单的多线程编程,就是通过pthread_create,pthread_join,pthread_exit 3个api实现线程的创建与终止,而创建的线程只做些简单的工作,如printf一些文字信息。
使用pthread_create,pthread_join,pthread_exit 进行多线程编程的模型如下图所示:
这里写图片描述

  1. pthread_create
//原型:int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void * (*start_routine)(void *), void *arg) 
/*
* @function :按照给定的线程属性attr,在一个进程(process)里创建一个新的线程(thread) 
* @param attr: 
*     如果attr为NULL,则内部使用默认的属性创建线程。如果在创建线程之后修改attr,则不会对已经创建的线程产生作用。 
* @param thread: 
*     创建线程成功后,将thread id存储在thread里,返回给调用者。否则thrad的值是未定义的。 
* @param start_routine: 
*     线程创建成功后,开始执行线程的入口函数start_routine。 
* @param arg: 
*     调用者通过arg指定线程入口函数start_routine专用的参数指针。 
* @return : 
*     0 创建成功返回0 
*     EAGAIN 超出了系统限制,如创建的线程太多,一个进程最多创建线程个数PTHREAD_THREADS_MAX。 
*     EINVAL attr 的值无效 
* @note pthread_create创建线程后,线程入口函数即开始执行,不需要显示控制start_routine开始执行。 
*     如果确实需要将此过程分为create和start2步来控制start_routine稍后执行, 
*     start_routine可以通过等待一个条件变量(condition variable)进行同步的方式实现。 
* Compile and link with -pthread.例如:gcc -lphread
*/ 
  1. pthread_exit
    /**
    • @function void pthread_exit(void *status)
    • 终止调用者线程,
    • @param status:
    • 通过status设置退出状态,与pthread_join配对使用
    • @return :
    • 无返回值,也不返回到其调用方。
    • @note
    • 如果调用线程尚未分离,则线程ID 和status 指定的退出状态将保持不变,直到应用程序调用pthread_join() 以等待该线程。
    • 否则,将忽略status。线程ID 可以立即回收。
      */
  2. pthread_join
    /**
    • @function int pthread_join(pthread_t thread, void **status);
    • 等待thread线程终止
    • 如果thread指代的线程还没有终止,将导致调用线程挂起,直到thread指代的线程终止为止。
    • @param thread:
    • 所等待的的终止线程
    • @param status:
    • 如果status的值不等于NULL,那么它的值是通过pthread_exit传递过来的。
    • @return :
    • 0 线程已经终止
    • ESRCH 多个线程不能等待同一个线程完成,否则仅有一个线程会成功完成。其他线程将终止,并返回ESRCH 错误。
    • EINVAL 一般表示thread是无效的参数
    • EDEADLK 检查到死锁状态
    • @note
    • 如果调用线程尚未分离,则线程ID 和status 指定的退出状态将保持不变,直到应用程序调用pthread_join() 以等待该线程。
    • 否则,将忽略status。线程ID 可以立即回收。
      */

三、多线程互斥:

1. 线程的互斥函数有:
     1. 互斥函数的初始化:pthread_mutex_init();
     2. 互斥函数的锁定函数pthread_mutex_lock();
     3. 互斥函数的解锁函数pthread_mutex_unlock();
     4. 互斥函数的销毁函数pthread_mutex_destroy()。

四、多线程同步:

1.  初始化
    * pthread_cond_t cond_ready=PTHREAD_COND_INITIALIZER;
2. 等待条件成熟
    * pthread_cond_wait(&cond_ready, &mut);
3. 设置条件成熟
    * pthread_cond_signal(&cond_ready);

五、代码

/*
* Filename : pthread.c
* Date     : 2017-04-24
* Author   : Chen-nan
* Description: 这个程序是测试线程的互斥访问的。即:多个线程同时对一个资源进行访问时候,为了保证所操作资源的原子性,一次只能一个线程访问。
* */
* #include <pthread.h>
#include <unistd.h>
#include <stdio.h>

pthread_t pthread[2] ;
int count = 0 ;
pthread_mutex_t mutex ;
/*线程A的函数*/
void * funa( ) {
    int i = 0 ;
    for( i=0 ; i<10 ; ++i ) {
        pthread_mutex_lock(  &mutex ) ;
        ++count ;
        printf( "chen is  : %d \n" , count ) ;
        pthread_mutex_unlock(  &mutex ) ;
    }
    pthread_exit(NULL) ;
} 
/*线程B的函数*/
void * funb( ) {
    int i = 0 ;
    for( i=0 ; i<5 ; ++i ) {
        pthread_mutex_lock(  &mutex ) ;
        ++count ;
        printf( "nan is  : %d \n" , count ) ;
        pthread_mutex_unlock(  &mutex ) ;
    }
    pthread_exit(NULL) ;
}

int  main ( int argc , char **argv ) {

    pthread_mutex_init( &mutex , NULL ) ;
    /*创建线程A*/
    pthread_create( &pthread[0] , NULL , funa , NULL ) ;
    /*创建线程B*/
    pthread_create( &pthread[1] , NULL , funb , NULL ) ;
    /*等待线程A完成*/
    pthread_join( pthread[0] , NULL ) ;
    /*等待线程B完成*/
    pthread_join( pthread[1] , NULL ) ;

    return 0 ;
}
/*
* Filename : pthread.c
* Date     : 2017-04-24
* Author   : Chen-nan
* Description: 这个程序是测试线程的同步访问的。即:多个线程按照一定顺序先后执行。
* */
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

pthread_t pthread[2] ;
int count = 0 ;
pthread_mutex_t mutex ;
/*创建条件变量,其实就是创建一个信号,通过发送信号,唤醒其他进程。*/
pthread_cond_t flag=PTHREAD_COND_INITIALIZER;
/*线程A的函数*/
void * funa( ) {
    int i = 0 ;
    for( i=0 ; i<10 ; ++i ) {
        pthread_mutex_lock(  &mutex ) ;
        ++count ;
        printf( "chen is  : %d \n" , count ) ;
        pthread_mutex_unlock(  &mutex ) ;
        if( 10==count ) {
            printf( "--------chen is finish .-------------\n")  ;
            /*条件成熟,发送条件变量(信号)通过其他进程可以开工了*/
            pthread_cond_signal(  &flag ) ;
        }
    }
    pthread_exit(NULL) ;
} 
/*线程B的函数*/
void * funb( ) {
    int i = 0 ;
    pthread_mutex_lock(  &mutex ) ;
    if( 10>count ) {
    /*判断当前条件是否可以执行,不行就挂起等待。直到有其他线程发送信号为止。这个函数包含了一个互斥锁,进入挂起状态时会解锁(所以前面有一个互斥锁的锁定),当收到信号后就会加上互斥锁(所以后边要解锁)。*/
        pthread_cond_wait( &flag  , &mutex ) ; 
    } 
    for( i=0 ; i<5 ; ++i ) {
        ++count ;
        printf( "nan is  : %d \n" , count ) ;
        pthread_mutex_unlock(  &mutex ) ;
    }
    pthread_exit(NULL) ;
}

int  main ( int argc , char **argv ) {

    pthread_mutex_init( &mutex , NULL ) ;
    /*创建线程A*/
    pthread_create( &pthread[0] , NULL , funa , NULL ) ;
    /*创建线程B*/
    pthread_create( &pthread[1] , NULL , funb , NULL ) ;
    /*等待线程A完成*/
    pthread_join( pthread[0] , NULL ) ;
    /*等待线程B完成*/
    pthread_join( pthread[1] , NULL ) ;

    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值