线程共享同一进程的地址空间
优点:
缺点:
同步指的是多个任务按照约定的先后次序互相配合完成一件事情。
1968年,Edsgar Dijkstra基于信号量的概念提出了一种同步机制。由信号量来决定线程是继续运行还是阻塞等待。
if(信号量的值大于0){
申请资源的任务继续运行;
信号量的值减一;
}
else{
申请资源的任务阻塞;
}
信号量的值加一;
if(有任务在等待资源){
唤醒等待的任务,让其继续运行;
}
Posix中定义了两种信号量:
>无名信号量(基于内存的信号量)
>有名信号量
下面将介绍无名信号量。
#include
int sem_init(sem_t* sem,int pshared,unsigned int val);
#include
int sem_wait(sem_t* sem); //P操作
int sem_post(sem_t* sem); //V操作
两个线程同步读写缓冲区
这个问题需要两个信号量实现读写的同步,一个信号量来描述可读缓冲区的数量,一个来描述可写缓冲区的数量。
#include
#include
#include
#include
char buf[32];
sem_t r;
sem_t w;
void* function(void* arg);
int main(void)
{
pthread_t a_thread;
if(sem_init(&r,0,0)<0) //创建可读缓冲区信号量,初始为0
{
perror("sem_init");
exit(-1);
}
if(sem_init(&w,0,1)<0) //创建可写缓冲区信号量
{
perror("sem_init");
exit(-1);
}
if(pthread_create(&a_thread,NULL,function,NULL)!=0)
{
printf("fail to pthread_create");
exit(-1);
}
printf("input 'quit' to exit\n");
do
{
sem_wait(&w);
fgets(buf,32,stdin);
sem_post(&r);
}while(strncmp(buf,"quit",4)!=0);
return 0;
}
void* function(void* arg)
{
while(1)
{
sem_wait(&r);
printf("you enter %d characters\n",strlen(buf));
sem_post(&w);
}
}
结果为
在写这段代码时,首先要主要到,创建信号量应在创建线程之前完成。防止出现还未创建信号量主线程的CPU时间片用完导致执行了新的线程,发生访问冲突。
#include
int pthread_mutex_init(pthread_mutex_t* mutex,const pthread_mutexattr_t* attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁
互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前有四个值可供选择:
enum
{
PTHREAD_MUTEX_TIMED_NP,
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_ADAPTIVE_NP
};
int pthread_mutex_lock(pthread_mutex_t *mutex);
int
__pthread_mutex_unlock (pthread_mutex_t *mutex)
#include
#include
#include
#include
unsigned int count,value1,value2;
pthread_mutex_t lock;
void* function(void* arg);
int main(void)
{
pthread_t a_thread;
if(pthread_mutex_init(&lock,NULL)!=0)
{
printf("fail to pthread_mutex_init\n");
exit(-1);
}
if(pthread_create(&a_thread,NULL,function,NULL)!=0)
{
printf("fail to pthread_create\n");
exit(-1);
}
while(1)
{
count++;
#ifdef _LOCK_
pthread_mutex_lock(&lock);
#endif
value1 = count;
value2 = count;
#ifdef _LOCK_
pthread_mutex_unlock(&lock);
#endif
}
return 0;
}
void* function(void* arg)
{
while(1)
{
#ifdef _LOCK_
pthread_mutex_lock(&lock);
#endif
if(value1 != value2)
{
printf("value1 = %u, value2 = %u\n",value1,value2);
usleep(100000);
}
#ifdef _LOCK_
pthread_mutex_unlock(&lock);
#endif
}
return NULL;
}
首先我们看不加锁的执行情况,我们可以发现会出现value1与value2不同情况。
枷锁之后的结果
我们可以分析出如果不加锁,那么当一个进程在执行value1 = count;
就可能发生时间片到执子线程,而此时可能value2还未被赋值,所以value1!=value2
。
这时我们使用互斥锁便能很好的解决同时访问临界区的问题。
如果你看到这觉得写得不错,那么可以帮我点一个赞再走吧^.^