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;
}



你可能感兴趣的:(thread,多线程,linux,null,buffer,insert)