POSIX信号量相关函数

sem_open

功能:
initialize and open a named semaphore
原型:
sem_t *sem_open(const char *name, int oflag);
参数:
name : 信号量的名字
oflag :
返回值:
成功 : 返回新信号量的地址
失败 : SEM_FAILED errno Link with -pthread

sem_close

功能:
close a named semaphore
原型:
int sem_close(sem_t *sem);
参数:
sem : 信号量
返回值:
成功 : 0
失败 : -1 errno Link with -pthread

sem_unlink

功能:
remove a named semaphore
原型:
int sem_unlink(const char *name);
参数:
name : 信号量
返回值:
成功 : 0
失败 : -1 errno Link with -pthread

sem_init

功能:
initialize an unnamed semaphore
原型:
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
sem : 信号量
pshared : 指示此信号量是在进程的线程之间还是在进程之间共享。
0 信号量在进程的线程之间共享,并且应位于所有线程可见的某个地址处(例如,全局变量或在堆上动态分配的变量)。
非零 则信号量在进程之间共享,并且应位于共享内存的区域中,任何可以访问共享的进程内存区域可以使用sem_post(3),sem_wait(3)等对信号量进行操作。
value : 初始值
返回值:
成功 : 0
失败 : -1 errno
注意:
虽然初始化的是一个匿名的信号量,它也可以用于不同进程间的多个线程间通信,取决于pshared非0和sem存放在共享内存中
Link with -pthread

sem_destroy

功能:
destroy an unnamed semaphore
原型:
int sem_destroy(sem_t *sem);
参数:
sem : 信号量
返回值:
成功 : 0
失败 : -1 errno Link with -pthread

sem_wait

功能:
lock a semaphore
原型:
int sem_wait(sem_t *sem);
参数:
sem : 信号量
返回值:
成功 : 0
失败 : -1 errno Link with -pthread

sem_post

功能:
unlock a semaphore
原型:
int sem_post(sem_t *sem);
参数:
sem : 信号量
返回值:
成功 : 0
失败 : -1 errno Link with -pthread

POSIX互斥锁相关函数

pthread_mutex_init

功能:
initialize a mutex
原型:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
参数:
mutex : 互斥锁
attr : 指定了新建互斥锁的属性。如果参数attr为空,则使用默认的互斥锁属性,默认属性为快速互斥锁
返回值:
成功 : 0
失败 : 返回对应的错误码

pthread_mutex_lock

功能:
lock a mutex
原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
参数:
mutex : 互斥锁
返回值:
成功 : 0
失败 : 返回对应的错误码

pthread_mutex_unlock

功能:
lock a mutex
原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数:
mutex : 互斥锁
返回值:
成功 : 0
失败 : 返回对应的错误码

pthread_mutex_destroy

功能:
destroy a mutex
原型:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数:
mutex : 互斥锁
返回值:
成功 : 0
失败 : 返回对应的错误码

生产者消费者问题

pctest.c

#include <unistd.h>
#include <sys/types.h>
#include <pthread.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #include <semaphore.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0) #define CONSUMERS_COUNT 1 //消费者线程的个数
#define PRODUCERS_COUNT 5 //生产者线程的个数 #define BUFFSIZE 10 //缓冲区的大小
int g_buffer[BUFFSIZE]; //存放产品的ID的缓冲区 unsigned short in = 0; //产品的生产位置
unsigned short out = 0; //产品的消费位置
unsigned short produce_id = 0; //当前正在生产的产品的id
unsigned short consume_id = 0; //当前正在消费的产品的id sem_t g_sem_full; //buffer满的信号量
sem_t g_sem_empty; //buffer空的信号量
pthread_mutex_t g_mutex; pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT]; //总线程数 void *consume(void *arg)
{
int i;
int num = (int)arg;
while (1)
{
printf("%d waiting buffer not empty\n", num);
sem_wait(&g_sem_empty);
pthread_mutex_lock(&g_mutex); for (i = 0; i < BUFFSIZE; ++i)
{
printf("%02d ", i);
if (g_buffer[i] == -1)
printf("%s", "null");
else
printf("%d ", g_buffer[i]); if (i == out)
{
printf("\t <-- consume");
} printf("\n");
} consume_id = g_buffer[out];
printf("%d begin consume producet %d \n", num, consume_id);
g_buffer[out] = -1;
out = (out + 1) % BUFFSIZE;
printf("%d end consume producet %d \n", num, consume_id++); pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem_full);
sleep(1);
} return NULL;
} void *produce(void *arg)
{
int i;
int num = (int)arg;
while (1)
{
printf("%d waiting buffer not full\n", num);
sem_wait(&g_sem_full);
pthread_mutex_lock(&g_mutex); for (i = 0; i < BUFFSIZE; ++i)
{
printf("%02d ", i);
if (g_buffer[i] == -1)
printf("%s", "null");
else
printf("%d ", g_buffer[i]); if (i == in)
{
printf("\t <-- produce");
} printf("\n");
} printf("%d begin produce producet %d \n", num, produce_id);
g_buffer[in] = produce_id;
in = (in + 1) % BUFFSIZE;
printf("%d end produce producet %d \n", num, produce_id++); pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem_empty);
sleep(5);
} return NULL;
} int main()
{ int i;
for (i = 0; i < BUFFSIZE; ++i)
{
g_buffer[i] = -1;
} sem_init(&g_sem_full, 0, BUFFSIZE);
sem_init(&g_sem_empty, 0, 0); pthread_mutex_init(&g_mutex, NULL); for (i = 0; i < CONSUMERS_COUNT; ++i)
{
pthread_create(&g_thread[i], NULL, consume, (void *)i);
} for (i = 0; i < PRODUCERS_COUNT; ++i)
{
pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, (void *)i);
} for (i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; ++i)
{
pthread_join(g_thread[i], NULL);
} sem_destroy(&g_sem_full);
sem_destroy(&g_sem_empty);
pthread_mutex_destroy(&g_mutex); return 0;
}

自旋锁

  • 自旋锁类似于互斥锁,它的性能比互斥锁更高
  • 自旋锁与互斥锁很重要的一个区别是,线程在申请自旋锁的时候,线程不会被挂起,它处于忙等待的状态

pthread_spin_init

功能:
initialize a spin lock object
原型:
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
参数:
lock : 自旋锁
pshared :
PTHREAD_PROCESS_SHARED 允许任何有权访问分配了旋转锁的内存的线程对旋转锁进行操作,即使已分配该旋转锁在多个进程共享的内存中
PTHREAD_PROCESS_PRIVATE 只能由在与初始化旋转锁的线程相同的进程中创建的线程操作 返回值:
成功 : 0
失败 : 返回错误编号

pthread_spin_destroy

功能:
destroy a spin lock object
原型:
int pthread_spin_destroy(pthread_spinlock_t *lock);
参数:
lock : 自旋锁
返回值:
成功 : 0
失败 : 返回错误编号

pthread_spin_lock

功能:
lock a spin lock object
原型:
int pthread_spin_destroy(pthread_spinlock_t *lock);
参数:
lock : 自旋锁
返回值:
成功 : 0
失败 : errno

pthread_spin_unlock

功能:
unlock a spin lock object
原型:
int pthread_spin_unlock(pthread_spinlock_t *lock);
参数:
lock : 自旋锁
返回值:
成功 : 0
失败 : errno

spinlockvsmutex1.cc

#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include <sys/time.h>
#include <list>
#include <pthread.h> #define LOOPS 50000000 using namespace std; list<int> the_list; #ifdef USE_SPINLOCK
pthread_spinlock_t spinlock;
#else
pthread_mutex_t mutex;
#endif //Get the thread id
pid_t gettid() { return syscall( __NR_gettid ); } void *consumer(void *ptr)
{
int i; printf("Consumer TID %lun", (unsigned long)gettid()); while (1)
{
#ifdef USE_SPINLOCK
pthread_spin_lock(&spinlock);
#else
pthread_mutex_lock(&mutex);
#endif if (the_list.empty())
{
#ifdef USE_SPINLOCK
pthread_spin_unlock(&spinlock);
#else
pthread_mutex_unlock(&mutex);
#endif
break;
} i = the_list.front();
the_list.pop_front(); #ifdef USE_SPINLOCK
pthread_spin_unlock(&spinlock);
#else
pthread_mutex_unlock(&mutex);
#endif
} return NULL;
} int main()
{
int i;
pthread_t thr1, thr2;
struct timeval tv1, tv2; #ifdef USE_SPINLOCK
pthread_spin_init(&spinlock, 0);
#else
pthread_mutex_init(&mutex, NULL);
#endif // Creating the list content...
for (i = 0; i < LOOPS; i++)
the_list.push_back(i); // Measuring time before starting the threads...
gettimeofday(&tv1, NULL); pthread_create(&thr1, NULL, consumer, NULL);
pthread_create(&thr2, NULL, consumer, NULL); pthread_join(thr1, NULL);
pthread_join(thr2, NULL); // Measuring time after threads finished...
gettimeofday(&tv2, NULL); if (tv1.tv_usec > tv2.tv_usec)
{
tv2.tv_sec--;
tv2.tv_usec += 1000000;
} printf("Result - %ld.%ldn", tv2.tv_sec - tv1.tv_sec,
tv2.tv_usec - tv1.tv_usec); #ifdef USE_SPINLOCK
pthread_spin_destroy(&spinlock);
#else
pthread_mutex_destroy(&mutex);
#endif return 0;
}

svm2.cc

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/syscall.h> #define THREAD_NUM 2 pthread_t g_thread[THREAD_NUM];
#ifdef USE_SPINLOCK
pthread_spinlock_t g_spin;
#else
pthread_mutex_t g_mutex;
#endif
__uint64_t g_count; pid_t gettid()
{
return syscall(SYS_gettid);
} void *run_amuck(void *arg)
{
int i, j; printf("Thread %lu started.n", (unsigned long)gettid()); for (i = 0; i < 10000; i++) {
#ifdef USE_SPINLOCK
pthread_spin_lock(&g_spin);
#else
pthread_mutex_lock(&g_mutex);
#endif
for (j = 0; j < 100000; j++) {
if (g_count++ == 123456789)
printf("Thread %lu wins!n", (unsigned long)gettid());
}
#ifdef USE_SPINLOCK
pthread_spin_unlock(&g_spin);
#else
pthread_mutex_unlock(&g_mutex);
#endif
} printf("Thread %lu finished!n", (unsigned long)gettid()); return (NULL);
} int main(int argc, char *argv[])
{
int i, threads = THREAD_NUM; printf("Creating %d threads...n", threads);
#ifdef USE_SPINLOCK
pthread_spin_init(&g_spin, 0);
#else
pthread_mutex_init(&g_mutex, NULL);
#endif
for (i = 0; i < threads; i++)
pthread_create(&g_thread[i], NULL, run_amuck, (void *) i); for (i = 0; i < threads; i++)
pthread_join(g_thread[i], NULL); printf("Done.n"); return (0);
}

总结

  1. Mutex适合对锁操作非常频繁的场景,并且具有更好的适应性。尽管相比spin lock它会花费更多的开销(主要是上下文切换),但是它能适合实际开发中复杂的应用场景,在保证一定性能的前提下提供更大的灵活度。

  2. spin lock的lock/unlock性能更好(花费更少的cpu指令),但是它只适应用于临界区运行时间很短的场景。而在实际软件开发中,除非程序员对自己的程序的锁操作行为非常的了解,否则使用spin lock不是一个好主意(通常一个多线程程序中对锁的操作有数以万次,如果失败的锁操作(contended lock requests)过多的话就会浪费很多的时间进行空等待)。

  3. 更保险的方法或许是先(保守的)使用 Mutex,然后如果对性能还有进一步的需求,可以尝试使用spin lock进行调优。毕竟我们的程序不像Linux kernel那样对性能需求那么高(Linux Kernel最常用的锁操作是spin lock和rw lock)。

读写锁

  • 只要没有线程持有给定的读写锁用于写,那么任意数目的线程可以持有读写锁用于读
  • 仅当没有线程持有某个给定的读写锁用于读或用于写时,才能分配读写锁用于写
  • 读写锁用于读 称为共享锁, 读写锁用于写 称为排它锁

pthread_rwlock_init

功能:
initialize a read-write lock object
原型:
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
参数:
rwlock : 读写锁指针
attr : 读写锁属性指针
返回值:
成功 : 0
失败 : 返回错误码

pthread_rwlock_destroy

功能:
destroy a read-write lock object
原型:
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
参数:
rwlock : 读写锁指针
返回值:
成功 : 0
失败 : 返回错误码

pthread_rwlock_rdlock

功能:
lock a read-write lock object for reading
原型:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
参数:
rwlock : 读写锁指针
返回值:
成功 : 0
失败 : 返回错误码

pthread_rwlock_wrlock

功能:
lock a read-write lock object for writing
原型:
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
参数:
rwlock : 读写锁指针
返回值:
成功 : 0
失败 : 返回错误码

pthread_rwlock_unlock

功能:
unlock a read-write lock object
原型:
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
参数:
rwlock : 读写锁指针
返回值:
成功 : 0
失败 : 返回错误码

rw_test.cc

#include <iostream>
#include <cstdlib> #include <unistd.h>
#include <pthread.h> using namespace std; struct{
pthread_rwlock_t rwlock;
int product;
}sharedData = {PTHREAD_RWLOCK_INITIALIZER, 0}; void * produce(void *ptr)
{
for (int i = 0; i < 5; ++i)
{
pthread_rwlock_wrlock(&sharedData.rwlock);
sharedData.product = i;
pthread_rwlock_unlock(&sharedData.rwlock); sleep(1);
}
} void * consume1(void *ptr)
{
for (int i = 0; i < 5;)
{
pthread_rwlock_rdlock(&sharedData.rwlock);
cout<<"consume1:"<<sharedData.product<<endl;
pthread_rwlock_unlock(&sharedData.rwlock);  ++i;
sleep(1);
}
} void * consume2(void *ptr)
{
for (int i = 0; i < 5;)
{
pthread_rwlock_rdlock(&sharedData.rwlock);
cout<<"consume2:"<<sharedData.product<<endl;
pthread_rwlock_unlock(&sharedData.rwlock); ++i;
sleep(1);
}
} int main()
{
pthread_t tid1, tid2, tid3; pthread_create(&tid1, NULL, produce, NULL);
pthread_create(&tid2, NULL, consume1, NULL);
pthread_create(&tid3, NULL, consume2, NULL); void *retVal; pthread_join(tid1, &retVal);
pthread_join(tid2, &retVal);
pthread_join(tid3, &retVal); return 0;
}

总结

第三十九章 POSIX信号量与互斥锁的更多相关文章

  1. Gradle 1.12用户指南翻译——第三十九章. IDEA 插件

    本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  2. “全栈2019”Java第三十九章:构造函数、构造方法、构造器

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  3. “全栈2019”Java多线程第二十九章:可重入锁与不可重入锁详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  4. POSIX信号量与互斥锁实现生产者消费者模型

    posix信号量 Link with -lpthread. sem_t *sem_open(const char *name, int oflag);//打开POSIX信号量 sem_t *sem_o ...

  5. linux网络编程之posix信号量与互斥锁

    继上次学习了posix线程之后,这次来讨论一下posix信号量与互斥锁相关的知识: 跟posix消息队列,共享内存的打开,关闭,删除操作一样,不过,上面的函数是对有名信号量进行操作,通过man帮助可以 ...

  6. posix信号量与互斥锁

    1.简介 POSIX信号量是一个sem_t 类型的变量,但POSIX 有两种信号量的实现机制:无名信号量和命名信号量.无名信号量可以用在共享内存的情况下, 比如实现进程中各个线程之间的互斥和同步.命名 ...

  7. linux网络编程-posix信号量与互斥锁(39)

    -posix信号量信号量 是打开一个有名的信号量 sem_init是打开一个无名的信号量,无名信号量的销毁用sem_destroy sem_wait和sem_post是对信号量进行pv操作,既可以使用 ...

  8. 【WPF学习】第三十九章 理解形状

    在WPF用户界面中,绘制2D图形内容的最简单方法是使用形状(shape)——专门用于表示简单的直线.椭圆.矩形以及多变形的一些类.从技术角度看,形状就是所谓的绘图图元(primitive).可组合这些 ...

  9. 第三十九章 微服务CICD(1)- gitlab搭建与使用(docker版)

    一.下载docker镜像 前提:docker引擎已经安装好. docker pull gitlab/gitlab-ce gitlab是8.13.1版本. 二.启动应用 docker run -d -h ...

随机推荐

  1. 在 Cocos Creator 中使用 Protobufjs(一)

    一. 环境准备 我一直在探索Cocos H5正确的开发姿势,目前做javascript项目已经离不开 nodejs.npm或grunt等脚手架工具了. 1.初始化package.json文件 npm ...

  2. 栈二:包含min函数的栈

    /** * 题目:包含min函数的栈 * 描述:  定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数.  *  注:用data来保存数据,用另一个栈min保存依次入栈最小的数 *  ...

  3. 分享8点超级有用的Python编程建议

    我们在用Python进行机器学习建模项目的时候,每个人都会有自己的一套项目文件管理的习惯,我自己也有一套方法,是自己曾经踩过的坑总结出来的,现在在这里分享一下给大家,希望多少有些地方可以给大家借鉴.

  4. Android实现apk插件方式换肤

    换肤思路: 1.什么时候换肤? xml加载前换肤,如果xml加载后换肤,用户将会看见换肤之前的色彩,用户体验不好. 2.皮肤是什么? 皮肤就是apk,是一个资源包,包含了颜色.图片等. 3.什么样的控 ...

  5. jsp隐含对象(内置对象)

    JSP共有以下9个内置的对象: request HttpServletRequest类的实例,用户端请求,此请求会包含来自GET/POST请求的参数 response HttpServletRespo ...

  6. Python多任务之协程

    前言 协程的核心点在于协程的使用,即只需要了解怎么使用协程即可:但如果你想了解协程是怎么实现的,就需要了解依次了解可迭代,迭代器,生成器了: 如果你只想看协程的使用,那么只需要看第一部分内容就行了:如 ...

  7. 2.linux系统基础笔记(延时操作、实时系统中的定时器、事件)

    延时操作 延时操作是操作系统中经常遇到的一种情形.延时的原因很多,有的时候是为了等待外设芯片处理结束,有的时候是为了暂时释放cpu的使用权,有的就是为了希望在一段时间获取资源,如果没法在单位时间内获取 ...

  8. 分库分表(6)--- SpringBoot+ShardingSphere实现分表+ 读写分离

    分库分表(6)--- ShardingSphere实现分表+ 读写分离 有关分库分表前面写了五篇博客: 1.分库分表(1) --- 理论 2.分库分表(2) --- ShardingSphere(理论 ...

  9. 寻找子串位置<codevs>

    KMP板子题; 如果不会可以参考其他算法书 代码: #include<iostream> #include<stdio.h> #include<stdlib.h> ...

  10. 部署主从dns

    主机部署:yum安装DNS服务和依赖 [admin@haifly-bj-dns1 ~]$ sudo yum install bind-chroot启动named-chroot服务 [admin@hai ...