一,共享数据
一组并发线程运行在一个进程的上下文中,每个线程都有它自己独立的线程上下文,包括线程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; }