之前有写过类似的博客,这东西不用老忘,现在又有更清晰的理解了。
一、信号量
编译时候加入-lrt
信号量最基本的两个操作就是PV操作:P()操作实现信号量减少,V()操作实现信号量的增加
信号量的值取决于信号量的类型,信号量的类型有多种:
(1)二进制信号量:0与1.
当值=1时,信号量可用,当值=0时候,信号量不可用,这里就可以利用P()V()操作来实现,如果=0时候,线程阻塞在P()操作
(2)计数信号量
某个非负整数,初始值表示可用的资源数,例如我们实现两个线程,一个线程专门执行V()操作 另一个专门执行P()操作 那么生产者,消费着的行为就是如此!!
//============================================================================ // Name : ThreadTest.cpp // Author : YLF // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <semaphore.h> #include <fcntl.h> #include <pthread.h> using namespace std; char *semName = "/SEM"; sem_t *sem; void* Producer(void* para){ int n = 10; while(n>0){ sem_post(sem); cout<<"produce"<<endl; n--; } } void* Consumer(void* para){ int n = 10; while(n>0){ sem_wait(sem); cout<<"consumer"<<endl; n--; } } int main() { sem = sem_open(semName, O_CREAT, O_RDWR, 0); pthread_t thread1,thread2; pthread_create(&thread1,NULL,Producer,NULL); pthread_create(&thread2,NULL,Consumer,NULL); pthread_join(thread1,NULL); pthread_join(thread2,NULL); sem_close(sem); sem_unlink(semName); return 0; }
produce produceconsumer consumer produce produce produce produce produce produce produce produce consumer consumer consumer consumer consumer consumer consumer consumer
我们发现,上面这种方式不是一个很好的原子操作!
当然,也可以利用0-1这种实现原子操作
就是将信号量初始化为1,然后Producer()和Consuer()这两个线程都执行
sem_wait()
受限制的资源操作
sem_post()
这种方式就可以阻塞另一个想要占用同一个资源的线程
信号量的好处就是可以实现进程间的通信!
二、POSIX还提供了另一种实现机制,利用MUTEX pthread_mutex_t
编译时候加入-lpthread
#include <pthread.h>
#include <fcntl.h>
这个互斥量的使用方式
初始化:
mutex = PTHREAD_MUTEX_INITIALIZER;//静态初始化
pthread_mutex_init(&mutex, NULL);//动态初始化
请求占有:
pthread_mutex_lock(&mutex)
释放占有:
pthread_mutex_unlock(&mutex);
尝试占有:
pthread_mutex_trylock(&mutex);
销毁:
pthread_mutex_destroy(&mutex);
三、读写锁
互斥量信号量都是临界区实现,只有使用共享数据的线程或进程才能进入。可是,当我们有多个线程只是希望读取数据的时候,他们之间会进行阻塞,而我们并不希望这样,只希望写线程才会对别的产生阻塞
如果多个线程对共享内存进行写访问,则不允许其他线程进入临界区,如果应用程序有多个线程希望读,则可以进入临界区。
POSIX定义了类型为pthread_rwlock_t 的读写锁
初始化:
pthread_rwlock_init(pthread_rwlock_t*, attr)
请求占有:
pthread_rwlock_rdlock(*lock)
pthread_rwlock_wrlock(*lock);
pthread_rwlock_timedrdlock()...
释放占有:
pthread_rwlock_unlock(*lock)
尝试和销毁
四、条件变量
互斥量通过 控制 对共享数据的访问来同步任务。条件变量可以根据数据的值来同步任务。条件变量是当一个事件发生时发送信号的信号量。一旦事情发生,可能会有多个进程或线程在等待信号。条件变量通常用于对操作的顺序进行同步。
条件变量类型pthread_cond_t
初始化:
pthread_cond_init(pthread_cond_t*,*attr)
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
发送信号:
pthread_cond_signal(*cond)
pthread_cond_broadcast(*cond)
销毁
pthread_cond_destroy(*cond);
阻塞:
pthread_cond_wait(*cond,*mutex)
pthread_mutex_t mutex, eventMutex;
pthread_cond_t cond;
void* ThreadA(void *para){
int num = 10;
while(num>0){
pthread_mutex_lock(&mutex);
num--;
cout<<"ThreadA:"<<num<<endl;
if(num == 6)
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
void* ThreadB(void* para){
int num = 10;
pthread_mutex_lock(&eventMutex);
pthread_cond_wait(&cond, &eventMutex);
pthread_mutex_unlock(&eventMutex);
while(num>0){
pthread_mutex_lock(&mutex);
num--;
cout<<"ThreadB:"<<num<<endl;
pthread_mutex_unlock(&mutex);
}
}
int main() {
pthread_mutex_init(&mutex, NULL);
pthread_mutex_init(&eventMutex, NULL);
pthread_t thread1,thread2;
pthread_create(&thread2,NULL,ThreadB,NULL);
pthread_create(&thread1,NULL,ThreadA,NULL);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
return 0 ;
}