【Linux】POSIX訊號量
阿新 • • 發佈:2018-12-30
POSIX訊號量和SystemV訊號量作⽤相同,都是⽤於同步操作,達到⽆衝突的訪問共享資源⺫的。 但POSIX可以⽤於執行緒間同步。
一個計數器+等待佇列,計數器用來標記當前是否有資源可供操作,等待佇列則是沒有資源就將pcb加入佇列中,等有資源的時候喚醒佇列中的執行緒。
訊號量的操作就是對計數器的+1/-1操作,當計數器<=0則表示沒有資源,這時候陷入等待;如果別人釋放了資源,喚醒等待。
訊號量用於實現程序/執行緒之間的同步與互斥。
初始化訊號量
int sem_init(sem_t *sem, int pshared, unsigned int value); 引數: pshared:0表⽰執行緒間共享,⾮零表⽰程序間共享 value:訊號量初始值 返回值:成功0;失敗:-1
銷燬訊號量
int sem_destroy(sem_t *sem);
獲取訊號量(等待訊號量)
功能:等待訊號量,會將訊號量的值減1
int sem_wait(sem_t *sem);判斷計數器是否大於零,大於零表示有資源可操作,這時候計數器-1,如果小於等於0代表沒有資源可操作,這時候則陷入等待
int sem_trywait();
int sem_timewait();
釋出訊號量
功能:釋出訊號量,表⽰資源使⽤完畢,可以歸還資源了。將訊號量值加1。
int sem_post(sem_t *sem);
實現執行緒同步
#include <iostream> #include<unistd.h> #include<stdlib.h> #include<semaphore.h> #include<errno.h> #include<pthread.h> using namespace std; sem_t sem; void* productor(void* arg) { while(1) { sleep(1); cout << "create noodle!!!" << endl; sem_post(&sem); } return NULL; } void* consumer(void* arg) { while(1) { sem_wait(&sem); cout << "eat noodle!!!" << endl; } return NULL; } int main() { pthread_t tid1,tid2; sem_init(&sem, 0, 0); pthread_create(&tid1, NULL, productor, NULL); pthread_create(&tid2, NULL, consumer, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); sem_destroy(&sem); return 0; }
實現執行緒互斥
#include <iostream> #include<unistd.h> #include<stdlib.h> #include<semaphore.h> #include<errno.h> #include<pthread.h> using namespace std; sem_t sem; void* productor(void* arg) { while(1) { sem_wait(&sem); cout << "create noodle!!!" << endl; sem_post(&sem); usleep(10); } return NULL; } void* consumer(void* arg) { while(1) { sem_wait(&sem); cout << "eat noodle!!!" << endl; sem_post(&sem); usleep(10); } return NULL; } int main() { pthread_t tid1,tid2; sem_init(&sem, 0, 1); pthread_create(&tid1, NULL, productor, NULL); pthread_create(&tid2, NULL, consumer, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); sem_destroy(&sem); return 0; }
用訊號量實現環形佇列
/*用vector實現環形佇列
* 使用訊號量來對這個環形佇列資源進行計數
* 兩個訊號量:
* 一個是空閒空間資源計數 等於vector節點數
* 一個是寫入資料的空間計數 初始值為0
*/
#include <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>
#include<vector>
using namespace std;
#define MAX_QUEUE 10
class RingQueue
{
private:
vector<int> _q;
int _cap;
int _consumer_step;
int _productor_step;
sem_t _idle;
sem_t _data;
public:
RingQueue(int cap = MAX_QUEUE):_cap(cap),_q(cap)
{
_consumer_step = 0;
_productor_step = 0;
sem_init(&_idle, 0, cap);
sem_init(&_data, 0, 0);
}
~RingQueue()
{
sem_destroy(&_data);
sem_destroy(&_idle);
}
bool GetData(int& data)
{
sem_wait(&_data);
data = _q[_consumer_step++];
_consumer_step %= _cap;
sem_post(&_idle);
return true;
}
bool PutData(int data)
{
sem_wait(&_idle);
_q[_productor_step++] = data;
_productor_step %= _cap;
sem_post(&_data);
return true;
}
};
void* consumer(void* arg)
{
RingQueue *q = (RingQueue*)arg;
while(1)
{
int data;
q->GetData(data);
cout << "data:" << data << endl;
}
return NULL;
}
void* productor(void* arg)
{
RingQueue *q = (RingQueue*)arg;
int i = 0;
while(1)
{
q->PutData(i++);
cout << "put data:" << i << endl;
}
return NULL;
}
int main()
{
RingQueue q;
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, consumer, (void*)&q);
pthread_create(&tid2, NULL, productor, (void*)&q);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}