互斥是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它 们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。
同步是散布在不同进程之间的若干程序片断,它们的运行必须严格按照规定的 某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。
临界资源:多个线程共享的资源
临界区:多个线程访问临界资源的代码段
因为进程中的线程共享了进程的虚拟地址空间,因此线程间通信将变得更加简单,但是缺点也随之而来:缺乏数据的访问控制容易造成数据混乱(因为大家都在争抢访问公共资源),导致程序结果出现二义性。
举个例子:
结果与我们的初衷完全不一样,这就是线程完全问题。
获取资源的时候:
1.寄存器中的值赋值为0
2.将寄存器中的值与内存的值交换
3.判断寄存器的值,得出结果
在第二步交换的过程中,系统通过xchgb交换操作,该操作是汇编代码,一次性完成,该操作保证了原子性。
1.互斥锁的初始化
int pthread_mutex_init(pthread_mutex_t *_mutex,_const pthread_mutex_mutexattr_t* _mutexattr)
2.加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
3.解锁
int pthread_mutex_unlock(pthread_mutex_t*mutex);
4.互斥锁的销毁
pthread_mutex_destroy (pthread_mutex_t*);
创建四个线程,每个线程在抢票时候进行加锁,结束后解锁。
#include
#include
#include
#define THREADCOUNT 4
int g_tickets = 100;
pthread_mutex_t lock_;
void* MyStartThread(void* arg)
{
(void)arg;
while(1)
{
pthread_mutex_lock(&lock_);
if(g_tickets > 0)
{
printf("i am thread %p, i have ticket %d\n", pthread_self(), g_tickets);
g_tickets--;
}
else
{
pthread_mutex_unlock(&lock_);
break;
}
pthread_mutex_unlock(&lock_);
}
return NULL;
}
int main()
{
pthread_mutex_init(&lock_, NULL);
pthread_t tid[THREADCOUNT];
for(int i = 0; i < THREADCOUNT; i++)
{
int ret = pthread_create(&tid[i], NULL, MyStartThread, NULL);
if(ret < 0)
{
perror("pthread_create");
return -1;
}
}
for(int i = 0; i < THREADCOUNT; i++)
{
pthread_join(tid[i], NULL);
}
pthread_mutex_destroy(&lock_);
return 0;
}
它可以使用在资源不满足的情况下处于休眠状态,让出CPU资源,而资源状态满足时唤醒线程
1.初始化
int pthread_cond_init(pthread_cond_t* cond,pthread_condattr_t* attr)
2.等待:将调用该接口的线程放到PCB等待队列当中
int pthread_cond_wait(pthread_cond_t* cond,pthread_mutex_t* mutex);
3.唤醒
int pthread_cond_siganl(pthread_cond_t* cond)
int pthread_cond_broadcast (pthread_cond_t*cond)
4.释放
int pthread_cond_destroy (pthread_cond_t* cond)
结合条件变量实战一下消费者模型:消费者吃面,生产者做面,当碗里没面时,将消费真放进pcb等待队列,做好后有生产者通知其出队,当碗里有面的时,将生产者放入pcb等待队列,当碗里吃完的时候由消费者通知其做面。
#include
#include
#include
#define THREADCOUNT 2
int g_bowl = 0;
pthread_mutex_t g_mut;
pthread_cond_t g_cond;
void* EatStart(void* arg)
{
while(1)
{
//eat
pthread_mutex_lock(&g_mut);
while(g_bowl <= 0)
{
pthread_cond_wait(&g_cond, &g_mut);
}
printf("i am %p, i eat %d\n", pthread_self(), g_bowl);
g_bowl--;
pthread_mutex_unlock(&g_mut);
pthread_cond_signal(&g_cond);
}
return NULL;
}
void* MakeStart(void* arg)
{
while(1)
{
//make
pthread_mutex_lock(&g_mut);
while(g_bowl > 0)
{
pthread_cond_wait(&g_cond, &g_mut);
}
g_bowl++;
printf("i am %p, i make %d\n", pthread_self(), g_bowl);
pthread_mutex_unlock(&g_mut);
pthread_cond_signal(&g_cond);
}
return NULL;
}
int main()
{
pthread_mutex_init(&g_mut, NULL);
pthread_cond_init(&g_cond, NULL);
pthread_t consume[THREADCOUNT], product[THREADCOUNT];
for(int i = 0; i < THREADCOUNT; i++)
{
int ret = pthread_create(&consume[i], NULL, EatStart, NULL);
if(ret < 0)
{
perror("pthread_create");
return -1;
}
ret = pthread_create(&product[i], NULL, MakeStart, NULL);
if(ret < 0)
{
perror("pthread_create");
return -1;
}
}
for(int i = 0; i < THREADCOUNT; i++)
{
pthread_join(consume[i], NULL);
pthread_join(product[i], NULL);
}
pthread_mutex_destroy(&g_mut);
pthread_cond_destroy(&g_cond);
return 0;
}