详解线程的信号量和互斥锁

  前言:有个问题感觉一直会被问道:进程和线程的区别?也许之前我会回答:

  • 进程:资源分配最小单位
  • 线程:轻量级的进程 是系统调度的最小单位 由进程创建 多个线程共享进程的资源

  但是现在我觉得一个比喻回答的更好:程序就像静止的火车,进程是运行的火车,线程是运行火车的每节车厢。

个人感觉理解远比背些概念性东西更好。

  一、线程

  通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。

  1、线程相关函数 

  • pthread_create函数

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);

注:Compile and link with -pthread.//编译时 要加-lpthread
功能:创建线程
参数1:线程的ID
参数2:NULL
参数3:线程处理函数
参数4: 传递给线程处理函数的参数
成功放回0 失败返回-1

  • pthread_join函数

#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);

功能:以阻塞的方式等待指定线程 主线程如果执行到此函数 将阻塞等待子线程结束

  程序1-1演示两个函数用法:

#include"my.h"

void *func(void *p)
{
    *(int*)p = 10;
    printf("%d\n",*(int *)p);
}

int main()
{
    int x=100;
    pthread_t id;
    int ret = pthread_create(&id,NULL,func,&x);
    if(ret<0)
    {
        perror("pthread_create");
        exit(-1);
    }
    pthread_join(id,NULL);
    return 0;

}

注:头文件“my.h”为自定义文件,详情请参考这篇博客:http://www.cnblogs.com/liudw-0215/p/8946879.html  

运行演示如下图:

  二、信号量

  信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。

  1、信号量相关函数

  • sem_init函数

sem_t s;

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

格式:sem_init(&s,0,n)
功能:初始化一个信号量的值为value
参数2:是否在进程间使用 一般总是0 表示不在进程间使用
参数3:计数器的初始值

  • sem_wait函数

int sem_wait(sem_t *sem);
把计数器减一 它会等待 直到信号量有个非零值才会执行减法操作
如果对值为0的信号量用sem_wait 这个函数会等待 直到其他线程增加该信号量的值 使其不再是0为止
如果对值为2的信号量调用sem_wait 线程会继续执行 但信号量的值会减一。
如果两个线程同时在sem_wait调用上等待同一个信号量变为非0值 那么当信号量 被第三个线程+1 只有一个等待线程开始对信号量-1
然后继续执行 另一个线程还继续等待。

  • sem_post函数

#include <semaphore.h>

int sem_post(sem_t *sem);

功能:把 计数器+1

  程序2-1介绍信号量使用

#include"my.h"

sem_t s;

void *fun(void *p)
{
    int i;
    int *pa = (int *)p;
    for(i=0;i<4;i++)
    {
        sem_wait(&s);//将计数器的值-1
        pa[i] +=i;
    }
    for(i=0;i<4;i++)
    {
        printf("%-02d",pa[i]);
    }
    printf("\n");
    return  NULL;
}

void *fun1(void *p)
{
    sem_wait(&s);//将计数器的值-1
    puts("fun1 run!");
    return NULL;
}

int main()
{
    int i=0,ret=0;
    int a[5]={0};
    sem_init(&s,0,0);//设置信号量的值为0
    pthread_t tid[2];
    ret = pthread_create(&tid[0],NULL,fun,a);
    if(ret<0)
    {
        perror("pthread_create");
        exit(-1);
    }
    ret = pthread_create(&tid[1],NULL,fun1,a);
    if(ret<0)
    {
        perror("pthread_create");
        exit(-1);
    }

    for(i=0;i<5;i++)
    {
        sem_post(&s);//将计数器的值+1
    }

    pthread_join(tid[0],NULL);
    pthread_join(tid[1],NULL);
    return 0;
}

运行演示如下图:

  三、互斥锁

  互斥锁: 只要被锁住,其他任何线程都不可以访问被保护的资源

  1、互斥锁相关函数

pthread_mutex_t m;

pthread_mutex_init(&m,NULL) //初始化互斥量
pthread_mutex_lock(&m);//对一个互斥量加锁 如果互斥量已经加锁 函数会一直等待 等到有线程把这个互斥量解锁后 再去加锁
pthread_mutex_unlock(&m);//对一个互斥量解锁 哪个线程加锁只能由这个线程解锁 别的线程不能 解锁

  程序3-1演示互斥锁应用:

#include"my.h"

pthread_mutex_t m;

void* thread_fun(void  *p)
{
    int i;
    pthread_mutex_lock(&m);//加锁
    for(i=0;i<3;i++)
    {
        printf("PID:%d tid:%lu\n",getpid(),pthread_self());
        sleep(1);
    }
    pthread_mutex_unlock(&m);//解锁
    pthread_exit(NULL);
}

int main()
{
    pthread_mutex_init(&m,NULL);//初始化锁
    int i,ret;
    pthread_t tid[3];
    for(i=0;i<3;i++)
    {
        ret = pthread_create(&tid[i],NULL,thread_fun,NULL);
        if(ret<0)
        {
            printf("pthread_create  %d error\n",i);
            exit(-1);
        }
    }

    for(i=0;i<3;i++)
    {
        pthread_join(tid[i],NULL);
    }
    return 0;
}

  运行演示如下图:

总结:主要介绍线程同步的信号量和互斥锁,以后有时间将更加详细介绍其中实现原理。

  

原文地址:https://www.cnblogs.com/liudw-0215/p/8966645.html

时间: 2024-10-13 02:35:45

详解线程的信号量和互斥锁的相关文章

线程同步机制之互斥锁

进程间通讯介绍 1.几种进程间的通信方式 # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. # 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信. # 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问.它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源.因此,主要作为进程间以及同一进

信号量、互斥锁,读写锁和条件变量的区别

信号量强调的是线程(或进程)间的同步:“信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都 在sem_wait的时候,就阻塞在那里).当信号量为单值信号量是,也可以完成一个资源的互斥访问.有名信号量:可以用于不同进程间或多线程间的互斥与同步 创建打开有名信号量 sem_t *sem_open(const char *name, int oflag); sem_t *sem_open(const char *name, int oflag

信号量与互斥锁

信号量与普通整型变量的区别: ①信号量(semaphore)是非负整型变量,除了初始化之外,它只能通过两个标准原子操作:wait(semap) , signal(semap) ; 来进行访问: ②操作也被成为PV原语(P来源于Dutch proberen"测试",V来源于Dutch verhogen"增加"),而普通整型变量则可以在任何语句块中被访问: 信号量与互斥锁之间的区别: 1. 互斥量用于线程的互斥,信号线用于线程的同步. 这是互斥量和信号量的根本区别,也就

条件变量、信号量、互斥锁

转载 http://blog.csdn.net/yusiguyuan/article/details/14161225 线程间的同步技术,主要以互斥锁和条件变量为主,条件变量和互斥所的配合使用可以很好的处理对于条件等待的线程间的同步问题.举个例子:当有两个变量x,y需要在多线程间同步并且学要根据他们之间的大小比较来启动不同的线程执行顺序,这便用到了条件变量这一技术.看代码 1 #include <iostream> 2 #include <pthread.h> 3 using na

POSIX信号量与互斥锁

POSIX信号量相关函数: sem_open sem_close sem_unlink sem_init sem_destroy sem_wait sem_post POSIX互斥锁 pthread_mutex_init pthreaad_mutex_lock pthread_mutex_unlock pthread_mutex_destroy 自旋锁 自旋锁类似于互斥锁,它的性能比互斥锁更高. 自旋锁与互斥锁很重要的一个区别在于,线程在申请自旋锁的时候,线程不会被挂起,它处于忙等待的状态. p

编程之美--信号量与互斥锁选择(转)

编程之美--多线程高效下载的问题 2011-03-27 15:27:12 分类: C/C++ 基本的思路: 这个问题相当于是生产者和消费者模型的问题 首先定义两个线程,一个是下载线程,一个是存储线程,下载线程将数据从网络上下载到相应的数据的缓冲区中(BLOCK组成的队列).存储的线程从数据缓冲区中读取相应的数据,并将其写到相应的磁盘上去. 多线程同步的方式有:CriticalSection.Mutex和Semaphore(信号量).因为CriticalSection和Mutex,将不会使下载线程

信号量与互斥锁区别

信号量与互斥锁之间的区别: 互斥量用于线程的互斥,信号线用于线程的同步.  这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别. 互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性.但互斥无法限制访问者对资源的访问顺序,即访问是无序的.  同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问.在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的.少数情况是指可以允许多个访问者同时访问资源 信号量经典举例 题目描述:白子和黑子

信号量与互斥锁的区别

之前遇到一个问题,信号量和互斥锁的区别是什么.一时忘了思考,今天才想到这个问题,翻阅知乎和stackoverflow,理解了之后做简单整理 一.定义 mutex,互斥锁,用于序列化对一部分可重入代码的访问,这些代码不能由多个线程同时执行 semaphore,信号量,将共享资源的并发用户数限制为最大数量 二.使用 Mutex:假设我们有关键部分线程T1想要访问它然后它遵循以下步骤: 锁 使用关键部分 开锁 二进制信号量:它基于信令等待和信号工作.等待(s)将"s"值减少一个通常"

重新学习MySQL数据库7:详解MyIsam与InnoDB引擎的锁实现

重新学习Mysql数据库7:详解MyIsam与InnoDB引擎的锁实现 说到锁机制之前,先来看看Mysql的存储引擎,毕竟不同的引擎的锁机制也随着不同. 三类常见引擎: MyIsam :不支持事务,不支持外键,所以访问速度快.锁机制是表锁,支持全文索引 InnoDB :支持事务.支持外键,所以对比MyISAM,InnoDB的处理效率差一些,并要占更多的磁盘空间保留数据和索引.锁机制是行锁,不支持全文索引(5.6以上支持) Memory:数据是存放在内存中的,默认哈希索引,非常适合存储临时数据,服