一,共享數據
一組併發線程運行在一個進程的上下文中,每個線程都有它自己獨立的線程上下文,包括線程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;
}