zoukankan      html  css  js  c++  java
  • 信号灯(线程互斥)

    现在不用了,别人自己写的

    信号灯与互斥锁和条件变量的主要不同在于""的概念,灯亮则意味着资源可用(即加锁),灯灭则意味着不可用(即解锁)。如果说后两种同步方式侧重于"等待"操作,即资源不可用的话,信号灯机制则侧重于点灯,即告知资源可用;没有等待线程的解锁或激发条件都是没有意义的,而没有等待灯亮的线程的点灯操作则有效,且能保持灯亮状态。当然,这样的操作原语也意味着更多的开销。

    信号灯的应用除了灯亮/灯灭这种二元灯以外,也可以采用大于1的灯数,以表示资源数大于1,这时可以称之为多元灯。

    1 创建和注销

    POSIX信号灯标准定义了有名信号灯无名信号灯两种,但LinuxThreads的实现仅有无名灯,同时有名灯除了总是可用于多进程之间以外,在使用上与无名灯并没有很大的区别,因此下面仅就无名灯进行讨论。

    #include <semaphore.h>

           int sem_init(sem_t *sem, int pshared, unsigned int value); //通常pshared0.表示线程间

           这是创建信号灯的API,其中value为信号灯的初值pshared表示是否为多进程共享而不仅仅是用于一个进程之间的多线程共享LinuxThreads没有实现多进程共享信号灯,因此所有非0值的pshared输入都将使sem_init()返回-1,且置errnoENOSYS。初始化好的信号灯由sem变量表征,用于以下点灯、灭灯操作。

           int sem_destroy(sem_t * sem);

           被注销的信号灯sem要求已没有线程在等待该信号灯,否则返回-1,且置errnoEBUSY。除此之外,LinuxThreads的信号灯注销函数不做其他动作。

     

    2 点灯和灭灯

           int sem_post(sem_t * sem);

           点灯操作将信号灯值原子地加1,表示增加一个可访问的资源。只有信号灯值大于0,才能访问公共资源。主要用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞。

     

           int sem_wait(sem_t * sem);

    int sem_trywait(sem_t * sem);

    sem_wait()为灭灯操作(等待灯亮操作),主要被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。等待灯亮(信号灯值大于0),然后将信号灯原子地减1,并返回。sem_trywait()sem_wait()的非阻塞版,如果信号灯计数大于0,则原子地减1并返回0,否则立即返回-1errno置为EAGAIN

     

    3 获取灯值

    int sem_getvalue(sem_t * sem, int * sval);

    读取sem中的灯计数,存于*sval中,并返回0

     

    4 其他

           sem_wait()被实现为取消点,而且在支持原子"比较且交换"指令的体系结构上,sem_post()是唯一能用于异步信号处理函数的POSIX异步信号安全的API

     

    Examplesem_post表示点灯(资源可用,V操作), sem_wait表示灭灯(资源不可用,P操作)

    #include<pthread.h>

    #include<stdio.h>

    #include <semaphore.h>   //头文件包含

    int ticketcount = 10;

    sem_t lock;

    void *chk1(void *args)

    {

           while(1)

    {

    sem_wait(&lock);  //因为要访问全局的共享变量ticketcount,所以就要加锁

        if(ticketcount > 0)  //如果有票

    {

    printf("windows1 start sale ticket!the ticket is:%d ",ticketcount);

            ticketcount --;//则卖出一张票

                         sleep(3);

            printf("sale ticket finish!,the last ticket is:%d ",ticketcount);

        }

        else   //如果没有票了,就解锁退出

        {

            sem_post(&lock);

            break;

        }

        sem_post(&lock);

        sleep(1);       //要放到锁的外面

    }

                  pthread_exit(NULL);

    }

    void *chk2(void *args)

    {

    while(1)

    {

    sem_wait(&lock);  //因为要访问全局的共享变量ticketcount,所以就要加锁

        if(ticketcount > 0)  //如果有票

    {

    printf("windows2 start sale ticket!the ticket is:%d ",ticketcount);

            ticketcount --;//则卖出一张票

                         sleep(3);

            printf("sale ticket finish!,the last ticket is:%d ",ticketcount);

        }

        else   //如果没有票了,就解锁退出

        {

            sem_post(&lock);

            break;

        }

        sem_post(&lock);

        sleep(1);       //要放到锁的外面

    }

          pthread_exit(NULL);

    }

    main()

    {

                pthread_t pthid1,pthid2;

                sem_init(&lock,0,1);     //信号灯值初始为1,表示资源可用

                pthread_create(&pthid1,NULL,chk1,NULL);

                pthread_create(&pthid2,NULL,chk2,NULL);

                         pthread_join(pthid1,NULL);

                pthread_join(pthid2,NULL);

                sem_destroy(&lock);

    }

  • 相关阅读:
    SharePoint 2013 配置基于表单的身份认证
    SharePoint 2013 场解决方案包含第三方程序集
    SharePoint 2010 站点附加数据升级到SP2013
    SharePoint 2013 在母版页中插入WebPart
    SharePoint 2013 搭建负载均衡(NLB)
    SharePoint 部署解决方案Feature ID冲突
    SharePoint 2013 配置基于AD的Form认证
    SharePoint Server 2016 Update
    SharePoint 2013 为用户组自定义EventReceiver
    SharePoint 2013 JavaScript API 记录
  • 原文地址:https://www.cnblogs.com/meihao1203/p/8531970.html
Copyright © 2011-2022 走看看