1.POSIX信号量
1.有名信号量
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
int sem_close(sem_t *sem);
int sem_unlink(const char *name);
2.匿名信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);
(1)匿名信号量只存在于内存中, 并要求使用信号量的进程必须可以访问内存; 这意味着他们只能应用在同一进程中的线程, 或者不同进程中已经映射相同内存内容到它们的地址空间中的线程.
(2)匿名信号量必须用sem_init 初始化,sem_init 函数的第二个参数pshared决定了线程共享(pshared=0)还是进程共享(pshared!=0),也可以用sem_post 和sem_wait 进行操作,在共享内存释放前,匿名信号量要先用sem_destroy 销毁
3.PV操作
int sem_wait(sem_t *sem); //P操作
int sem_post(sem_t *sem); //V操作
(2)post操作将信号量加1, 在调用sem_post时, 如果在调用sem_wait中发生了进程阻塞, 那么进程会被唤醒并且sem_post增1的信号量计数会再次被sem_wait减1;
2.POSIX互斥锁
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutexattr); //互斥锁初始化, 注意:函数成功执行后,互斥锁被初始化为未锁住状态。
int pthread_mutex_lock(pthread_mutex_t *mutex); //互斥锁上锁
int pthread_mutex_trylock(pthread_mutex_t *mutex); //互斥锁判断上锁
int pthread_mutex_unlock(pthread_mutex_t *mutex); //互斥锁解锁
int pthread_mutex_destroy(pthread_mutex_t *mutex); //消除互斥锁
3.生产者和消费者问题
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.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];
unsigned short in = 0;
unsigned short out = 0;
unsigned short produce_id = 0;
unsigned short consume_id = 0;
sem_t g_sem_full;
sem_t g_sem_empty;
pthread_mutex_t g_mutex;
pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT];
void* consume(void* arg) {
int i;
int num = *(int*)arg;
free(arg);
while(1) {
printf("%d wait 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 product %d\n", num, consume_id);
g_buffer[out] = -1;
out = (out+1) % BUFFSIZE;
printf("%d end consume product %d\n", num, consume_id);
pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem_full);
sleep(5);
}
return NULL;
}
void* produce(void* arg) {
int i;
int num = *(int*)arg;
free(arg);
while(1) {
printf("%d wait 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 product %d\n", num, produce_id);
g_buffer[in] = produce_id;
in = (in+1) % BUFFSIZE;
printf("%d end produce product %d\n", num, produce_id++);
pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem_empty);
sleep(1);
}
return NULL;
}
int main(int argc, char* argv[]) {
int i;
for(i=0; i<BUFFSIZE; i++) {
g_buffer[i] = -1;
}
//sem_init(第二个参数不为0,表示可用于不同进程间的线程通信,可以将信号放到共享内存中
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++) {
int* p = (int*)malloc(sizeof(int));
*p = i;
pthread_create(&g_thread[i], NULL, consume, (void*)p);
}
for(i=0; i<PRODUCERS_COUNT; i++) {
int* p = (int*)malloc(sizeof(int));
*p = i;
pthread_create(&g_thread[CONSUMERS_COUNT+i], NULL, produce, (void*)p);
}
for(i=0; i<CONSUMERS_COUNT+PRODUCERS_COUNT; i++) {
pthread_join(g_thread[i], NULL);
}
// sem_destory(&g_sem_full);
// sem_destory(&g_sem_empty);
// pthread_mutex_destory(&g_mutex);
return 0;
}
4.自旋锁
int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
int pthread_spin_unlock(pthread_spinlock_t *lock);
(1)自旋锁类似于互斥锁, 它的性能比互斥锁更高;
(2)自旋锁与互斥锁很重要的一个区别在于: 线程在申请自旋锁的时候, 线程并不会挂起, 它总是处于忙等待的状态(一直在自旋, CPU处于空耗的状态);
(3)自旋锁可用于以下情况:锁被持有的时间短, 而且线程并不希望在重新调度上花费太多的成本.
(4)自旋锁通常作为底层原语用于实现其他类型的锁: 比如有些互斥锁的实现在试图获取互斥量的时候会自旋一小段时间, 只有在自旋计数到达某一阈值的时候才会休眠; 因此, 很多互斥量的实现非常搞笑, 以至于应用程序采用互斥锁的性能与曾经采用过自旋锁的性能基本上是相同的.
(5)因此, 自旋锁只在某些特定的情况下有用, 比如在用户层, 自旋锁并不是非常有用, 除非运行在不允许抢占的实时调度类中.
5.读写锁
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
(1)读写锁与互斥量类似, 不过读写锁允许更高的并行性. 读写锁用于读称为共享锁, 读写锁用于写称为排它锁;
(2)只要没有线程持有给定的读写锁用于写, 那么任意数目的线程可以持有读写锁用于读;
(3)仅当没有线程持有某个给定的读写锁用于读或用于写时, 才能分配读写锁用于写;