一、多线程的售票引发的问题
多线程间Linux下线程和线程共享全局变量、代码段、数据段、文件描述符表,这么多的临界资源在使用时也可能会带来一些麻烦
例如:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int ticket = 100;
void *route(void *arg)
{
char *id = (char*)arg;
while ( 1 ) {
if ( ticket > 0 ) {
usleep(1000);
printf("%s sells ticket:%d\n", id, ticket);
ticket--;
} else {
break;
}
}
}
int main()
{
pthread_t t1, t2, t3;
pthread_create(&t1, NULL, route, "thread 1");
pthread_create(&t2, NULL, route, "thread 2");
pthread_create(&t3, NULL, route, "thread 3");
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_join(t3,NULL);
}
不同的执行流对同一个全局变量进行操作,这个操作不是原子的。从内存读到CPU中,CPU中进行操作,操作后写回到内存中,步骤2完成后进程切换出去,保存操作2之后的数据进行等待,后续线程依然从起始的数开始操作,等所有的操作完成后都一起返回,第一个操作返回的数据是第一次操作后的。
第一个线程在CPU中将100张票减一后被切换出CPU,此时内存中的票数还是100张,线程2从内存中读取出票数进行减减操作(还是从100开始减减)等所有的进程都操作完成后线程一写回内存时票数是当时操作完的99张。造成一张票被卖出多次的情况。
这时就需要使用线程的同步与互斥机制保护临界资源,互斥说明一个线程在操作临界资源时其他线程不能访问临界资源,同步说明多个线程在访问临界资源时是按照一定顺序访问的。
二、线程互斥锁
线程中 互斥:互斥锁
定义互斥锁:pthread_mutex_t lock;
初始化:pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
mutex:要初始化的互斥量
attr:NULL
销毁:pthread_mutex_destroy(pthread_mutex_t *mutex);
注意不要销毁一个已经加锁的互斥量,已经销毁的互斥量要确保后面不会再次被加锁
加锁:pthread_lock(pthread_mutex_t *mutex);
解锁:pthread_unclock(pthread_mutex_t *mutex);
加锁和解锁成功返回0,失败返回错误码。
其他线程已经锁定互斥量,或者存在其他线程同时申请互斥量,但没有竞争到互
斥量,那么pthread_ lock调⽤会陷⼊阻塞,等待互斥量解锁。
三、生产者消费者模型
三个关系:生产者与生产者之间互斥关系,生产者与消费者之间互斥且同步关系(放的同时取,是放还是没放,取还是没取二义性;必须有人买才能添加,必须有人添加才能消费)消费者与消费者之间互斥关系,使用互斥锁。
两个角色:生产者消费者
一个场所:只要能存取数据就可以
实现一个生产场所为带头单链表的生产者消费者模型:
**因为优先级或避免竞争能力强的线程不断的获取锁释放锁,另一个进程得不到锁,饥饿问题数据
条件变量可以很好的解决
条件变量:线程间同步,当⼀个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了只能等待。直到其他线程将状态改变例如,消费者互斥的访问链表消费场所为空时消费者就一直等待,等待生产者生产一个结点加入链表,pthread_cond_wait()必须与互斥锁配合使用
如果不符合条件就不获取锁int pthread_cond_wait()等的时候默认释放锁,等的时候什么都不干,如果不释放锁没人释放了别的线程不能获取到锁,造成了死锁问题(已经进入获取到锁了),被signal或其他方式唤醒时重新获得锁并从等待处继续执行
1 //单生产者单消费者
2 //带头的单向链表作为交易场所
3 #include <stdio.h>
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <pthread.h>
7 #include <sys/syscall.h>
8 #include <stdlib.h>
9 #include <pthread.h>
10 typedef struct _Node
11 {
12 int data;
13 struct _Node *next;
14 }node_t,*node_p,**node_pp;
15 pthread_mutex_t lock;
16 pthread_cond_t cond;
17 node_p Create_Node(int data)
18 {
19 node_p new_node = (node_p)malloc(sizeof(node_t));
20 if(new_node == NULL)
21 {
22 perror("malloc\n");
23 exit(1);
24 }
25 new_node->data = data;
26 new_node->next = NULL;
27 return new_node;
28 }
29
30 void DestroyNode(node_p to_delete)
31 {
32 if(to_delete != NULL)
33 {
34 free(to_delete);
35 to_delete = NULL;
36 }
37 }
38 void Init_List(node_pp head)
{
40 // head = Create_Node(0);
41 *head = Create_Node(0);
42 }
43
44 void Link_Push(node_p head,int num)
45 {
46 node_p new_node = Create_Node(num);
47 new_node->next = head->next;
48 head->next = new_node;
49 }
50
51 void List_Pop(node_p head,int *num)//输出型参数
52 {
53 if(head->next != NULL)
54 {
55 node_p to_delete = head->next;
56 *num = to_delete->data;
57 head->next = to_delete->next;
DestroyNode(to_delete);
59 }
60 }
61
62 void PrintList(node_p head)
63 {
64 node_p cur = head->next;
65 if(cur != NULL)
66 {
67 printf("%d | %p\n",cur->data, cur);
68 cur = cur->next;
69 }
70 }
71
72 void DestroyList(node_p head)
73 {
74 int x;
75 node_p cur = head->next;
76 if(cur != NULL)
77 {
78 List_Pop(head,&x);
79 cur = cur->next;
80 }
81 free(head);
82 }
83
84 void *consumer(void *arg)
85 {
86 node_p head = (node_p )arg;
87 while(1)
88 {
89 int data = 0;
90 pthread_mutex_lock(&lock);
91 while(head->next == NULL)
92 {
93 printf("no data for consume\n");//什么都没干就只有申请锁释放锁
94 pthread_cond_wait(&cond,&lock);//没有数据不可以消费就等待,释放锁,条件变量实现了同步
95 //可能被异常唤醒,消费场所里还是没有数据while循环进行判断
96 }
97 List_Pop(head,&data);
98 printf("consumer done! data = %d\n",data);
99 pthread_mutex_unlock(&lock);//退出前解锁
100 sleep(1);
101 }
102 }
103
104 void *producter(void *arg)
105 {
106 node_p head = (node_p )arg;
107 while(1)
108 {
109 int data = 0;
110 data = rand()%100+1;
111 pthread_mutex_lock(&lock);
112 Link_Push(head,data);//放入消费场所
113 pthread_mutex_unlock(&lock);
114 //pthread_cond_signal(&cond);//放入后唤醒等待条件变量
115 pthread_cond_broadcast(&cond);//通知所有的线程
116 printf("product down data = %d\n",data);
117 sleep(5);
118 }
119 }
120 int main()
121 {
122 pthread_mutex_init(&lock,NULL);
123 pthread_cond_init(&cond,NULL);
124 node_p head;
125 Init_List(&head);
126 srand((unsigned long)time(NULL));
127 pthread_t p,c;
128 pthread_create(&c,NULL,consumer,(void *)head);
129 pthread_create(&p,NULL,producter,(void *)head);
130
131 pthread_join(c,NULL);
132 pthread_join(p,NULL);
133 pthread_mutex_destroy(&lock);
134 pthread_cond_destroy(&cond);
135 }