linux多線程學習筆記三---線程同步之信號量

一,共享數據

一組併發線程運行在一個進程的上下文中,每個線程都有它自己獨立的線程上下文,包括線程ID、棧、棧指針、程序計數器、條件代碼和通用寄存器。每個線程和其他線程一起共享進程上下文的剩餘部分。包括整個用戶虛擬地址空間,它是由只讀文本、讀寫數據、堆以及所有的共享庫代碼和數據區域組成的。線程也共享同樣的打開文件的集合。所以任何線程都可以訪問共享虛擬存儲器的任意位置。如果某個線程修改了一個存儲器位置,那麼其他每個線程最終都能在它讀這個位置時發現這個變化。

多線程的C程序中的變量根據他們的存儲類型被映射到虛擬存儲器。

全局變量:全局變量定義在外的變量。在運行函數之時,虛擬存儲器的讀/寫區域只包含每個全局變量的一個實例。本地自動變量:本地自動變量就是定義在函數內部但沒有static屬性的變量。在運行時,每個線程的棧都包含它自己的所有本地自動變量的實例。即使多個線程執行同一個線程程。因爲線程擁有自己的棧空間。本地靜態變量:本地靜態變量是定義在函數內部並有static屬性的變量。和全局變量一樣,虛擬存儲器的讀/寫區域只包含在程序中聲明的每個本地靜態變量的一個實例。由此可知全局變量和本地靜態變量都屬於共享變量。

二,用信號量同步線程
共享變量十分方便,同時也引入同步錯誤的可能性。,可以通過信號量來同步線程。Posix信號量的三個基本操作時sem_init,sem_wait和sem_post,學過操作系統的都知道PV操作,其中的sem_wait相當於P操作,sem_post相當於V操作.

#include<semaphore.h>
int sem_init(sem_t *sem,0,unsigned int value);
int sem_wait(sem_t*s);
int sem_post(sem_t*s);
返回:若成功爲0,若出錯則爲-1
看如下代碼:

#include<pthread.h>
#include<stdio.h>
#include<semaphore.h>
#define NITERS 100000000
/*共享變量*/
unsigned int cnt = 0;
sem_t mutex;
void *count(void *arg)
{
	int i;
	for(i=0;i<NITERS;i++)
	{
		sem_wait(&mutex);
		cnt++;
		sem_post(&mutex);
	}
	return arg;
}
int main()
{
	pthread_t tid1,tid2;
	int status;
	sem_init(&mutex,0,1);
	status=pthread_create(&tid1,NULL,count,NULL);
	if(status!=0)
	{
		printf("create error\n");
		return 1;
	}
	status=pthread_create(&tid2,NULL,count,NULL);
	if(status!=0)
	{
		printf("create error\n");
		return 1;
	}
	status=pthread_join(tid1,NULL);
	if(status!=0)
	{
		printf("join error\n");
		return 1;
	}
	status=pthread_join(tid2,NULL);
	if(status!=0)
	{
		printf("join error\n");
		return 1;
	}
	if(cnt!=(unsigned)NITERS*2)
		printf("Boom!,cnt=%d\n",cnt);
	else
		printf("Ok cnt=%d\n",cnt);
	return O;
}
若沒加信號量時運行結果爲:Boom!,cnt=120924615  加上信號量後爲:Ok cnt=200000000,通過信號量使線程互斥的執行cnt++。

三,利用信號量來調度資源共享資源
信號量的另一個重要作用是調度對共享資源的訪問。對經典的生產者消費者模型,,生產者和消費者共享一個有n個槽的有界緩衝區,生產者把產品生產放入緩衝區中,消費者從緩衝區中取商品。因爲插入和取出項目都包括更新共享變量,所有可以通過信號量實現互斥的訪問。同時還要考慮當緩衝區滿時,生產者必須等待,緩衝區空的時候消費者必須等待,這就涉及到資源的調度問題。

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>
/* $begin sbuft */
typedef struct {
    int *buf;          /* Buffer array */         
    int n;             /* Maximum number of slots */
    int front;         /* buf[(front+1)%n] is first item */
    int rear;          /* buf[rear%n] is last item */
    sem_t mutex;       /* Protects accesses to buf */
    sem_t slots;       /* Counts available slots */
    sem_t items;       /* Counts available items */
} sbuf_t;
/* $end sbuft */

void sbuf_init(sbuf_t *sp, int n);
void sbuf_deinit(sbuf_t *sp);
void sbuf_insert(sbuf_t *sp, int item);
int sbuf_remove(sbuf_t *sp);
void *producer_thread(void *arg);
void *consumer_thread(void *arg);
sbuf_t sbuf;
int main()
{
	pthread_t producer_id,consumer_id;
	sbuf_init(&sbuf,10);
	pthread_create(&producer_id,NULL,producer_thread,NULL);
	pthread_create(&consumer_id,NULL,consumer_thread,NULL);
	pthread_join(producer_id,NULL);
	pthread_join(consumer_id,NULL);
//	sbuf_deinit(&sbuf);
	return 0;
}
/* Create an empty, bounded, shared FIFO buffer with n slots */
/* $begin sbuf_init */
void sbuf_init(sbuf_t *sp, int n)
{
    sp->buf = (int*)malloc(n* sizeof(int)); 
    sp->n = n;                       /* Buffer holds max of n items */
    sp->front = sp->rear = 0;        /* Empty buffer iff front == rear */
    sem_init(&sp->mutex, 0, 1);      /* Binary semaphore for locking */
    sem_init(&sp->slots, 0, n);      /* Initially, buf has n empty slots */
    sem_init(&sp->items, 0, 0);      /* Initially, buf has zero data items */
}
/* $end sbuf_init */

/* Clean up buffer sp */
/* $begin sbuf_deinit */
void sbuf_deinit(sbuf_t *sp)
{
    free(sp->buf);
}
/* $end sbuf_deinit */

/* Insert item onto the rear of shared buffer sp */
/* $begin sbuf_insert */
void sbuf_insert(sbuf_t *sp, int item)
{
    sem_wait(&sp->slots);                          /* Wait for available slot */
    sem_wait(&sp->mutex);                          /* Lock the buffer */
    sp->buf[(++sp->rear)%(sp->n)] = item;   /* Insert the item */
    printf("insert item %d\n",item);
    sem_post(&sp->mutex);                          /* Unlock the buffer */
    sem_post(&sp->items);                          /* Announce available item */
}
/* $end sbuf_insert */

/* Remove and return the first item from buffer sp */
/* $begin sbuf_remove */
int sbuf_remove(sbuf_t *sp)
{
    int item;
    sem_wait(&sp->items);                          /* Wait for available item */
    sem_wait(&sp->mutex);                          /* Lock the buffer */
    item = sp->buf[(++sp->front)%(sp->n)];  /* Remove the item */
    printf("remove item %d\n",item);
    sem_post(&sp->mutex);                          /* Unlock the buffer */
    sem_post(&sp->slots);                          /* Announce available slot */
    return item;
}
/* $end sbuf_remove */
void* producer_thread(void *arg)
{
	int i=0;
	for(;i<20;i++)
	{
		sbuf_insert(&sbuf,i);
		//printf("insert item %d\n",i);
	}
	return NULL;
}
void* consumer_thread(void *arg)
{
	int i=0,item;
	for(;i<20;i++)
	{
		item=sbuf_remove(&sbuf);
		
	}
	return NULL;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章