下面写个多个线程操作共享变量来抢票的售票系统代码:
1.为什么可能无法获得争取结果?
if 语句
判断条件为真以后,代码可以并发的切换到其他线程。usleep
这个模拟漫长业务的过程中,可能有很多个线程会进入该代码段。ticket--
操作本身就不是一个原子操作。要做到这三点,本质上就是需要一把锁。Linux上提供的这把锁叫互斥量(mutex)。
互斥量加锁和解锁:
注意:在特定线程/进程拥有锁的期间,有新的线程来申请锁,pthread_ mutex_lock调用会陷入阻塞(执行流被挂起),等待互斥量解锁。unlock之后对线程进程唤醒操作。此外,加锁的粒度越小越好。
每个线程的寄存器是私有的,在修改数据的时候用的不是拷贝而是xchgb交换,将寄存器的值和内存的值互换。这保证了锁的原子性。因为其他线程申请的话,内存的值为0,申请不到锁。lock:0表示被占, 1表示可以被申请。
- 不保护共享变量的函数
- 函数状态随着被调用,状态发生变化的函数
- 返回指向静态变量指针的函数
- 调用线程不安全函数的函数
死锁是指在一组进程中的各个进程均占有不会释放的资源,但因为互相申请被其他进程所占用而不会释放的资源,而处于的一种永久等待状态。
同步概念:在保证数据安全(一般使用加锁方式
)的情况下,让线程能够按照某种特定的顺序访问临界资源,就叫做同步。
同步实现的事情:当有资源的时候,可以直接获取资源,没有资源的时候,线程进行等待,等待另外的线程生产一个资源,当生产完成的时候,通知等待的线程。
竞态条件:因为时序问题,而导致程序异常,我们称之为竞态条件。在线程场景下,这种问题也不难理解。
条件变量的本质:PCB等待队列+两个接口(等待接口+唤醒接口)
pthread_cond_t 条件变量类型
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
参数:
cond:传入条件变量的地址
attr:条件变量的属性,一般设置为NULL,采用默认属性
int pthread_cond_destroy(pthread_cond_t *cond)
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数:
cond:传入条件变量的地址
restrict mutex:传入互斥锁变量的地址
int pthread_cond_signal(pthread_cond_t *cond);
参数:
cond:传入条件变量的地址
//唤醒至少一个PCB等待队列当中的线程
#include
#include
#include
pthread_mutex_t lock;
pthread_cond_t cond;
void *task_t2(void *arg)
{
const char *name = (char*)arg;
while(1){
pthread_cond_wait(&cond, &lock);
printf("get cond : %s 活动...\n", name);
}
}
void *task_t1(void *arg)
{
const char *name = (char*)arg;
while(1){
sleep(rand()%3+1);
pthread_cond_signal(&cond);
printf("%s signal done...\n", name);
}
}
int main()
{
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
pthread_t t1,t2,t3,t4,t5;
pthread_create(&t1, NULL, task_t1, "thread1");
pthread_create(&t2, NULL, task_t2, "thread2");
pthread_create(&t3, NULL, task_t2, "thread3");
pthread_create(&t4, NULL, task_t2, "thread4");
pthread_create(&t5, NULL, task_t2, "thread5");
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_join(t4, NULL);
pthread_join(t5, NULL);
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
return 0;
}