在多线程中,如果多线程同时在访问同一个全局变量,就会出现多个线程在获取变量值时候获取的是同一个值,此时在线程中操作这个变量就会出现不同步的效果。下面这幅图就能够演示出对应的效果。可以使用线程的互斥锁来解决这样的问题。
- #include
- #include
- #include
- #include
-
- #define ERROR(msg) do{\
- printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
- printf(msg);\
- exit(-1); \
- }while(0)
-
- pthread_mutex_t lock;
- int money = 1000;
-
- void* task1(void* argc)
- {
- while (1){
- sleep(1);
- pthread_mutex_lock(&lock);
-
- if (money > 0){
- money -= 50;
- printf("张三取了50块钱,还剩下%d\n",money);
- }else {
- printf("张三取钱失败\n");
- }
-
- pthread_mutex_unlock(&lock);
- }
- }
- void* task2(void* argc)
- {
- while (1){
- sleep(1);
- pthread_mutex_lock(&lock);
-
- if (money > 0){
- money -= 100;
- printf("李四取了100块钱,还剩下%d\n",money);
- }else {
- printf("李四取钱失败\n");
- }
-
- pthread_mutex_unlock(&lock);
- }
- }
-
-
- int main(int argc, char const *argv[])
- {
- pthread_t pid1, pid2;
- pthread_mutex_init(&lock, NULL);
-
- if (pthread_create(&pid1, NULL, task1, NULL)){
- ERROR("创建失败");
- }
-
- if (pthread_create(&pid2, NULL, task2, NULL)){
- ERROR("create error");
- }
-
- pthread_join(pid1, NULL);
- pthread_join(pid2, NULL);
-
- pthread_mutex_destroy(&lock);
- return 0;
- }
线程同步,提前已经知道线程的执行顺序,让线程顺序执行的过程就是同步。
典型的就是生产者和消费者模型。
- #include
- #include
- #include
- #include
-
- #define ERROR(msg) do{\
- printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
- printf(msg);\
- exit(-1); \
- }while(0)
-
- sem_t sem1, sem2;
-
- void* task1(void* argc)
- {
- while(1){
- sem_wait(&sem1);
- printf("我生产了一辆汽车\n");
- sem_post(&sem2);
- }
- }
-
- void* task2(void* argc)
- {
- while(1){
- sem_wait(&sem2);
- printf("我买了一辆汽车\n");
- sem_post(&sem1);
- }
- }
-
-
- int main(int argc, char const *argv[])
- {
- pthread_t pid1, pid2;
- sem_init(&sem1, 0, 1);
- sem_init(&sem2, 0, 0);
-
- if (pthread_create(&pid1, NULL, task1, NULL)){
- ERROR("create error");
- }
-
- if (pthread_create(&pid2, NULL, task2, NULL)){
- ERROR("create error");
- }
-
- pthread_join(pid1, NULL);
- pthread_join(pid2, NULL);
-
- sem_destroy(&sem1);
- sem_destroy(&sem2);
- return 0;
- }
-
无名信号量适合在线程数比较少的线程中实现同步过程,而条件变量适合在大量线程
实现同步过程。例如条件变量的使用场景如下:比如你要编写一个12306买票的服务器
当客户端访问服务器的时候,服务器会创建一个线程服务于这个用户。如果有多个用户
同时想买票,此时服务需要在瞬间创建一堆线程,这个时间比较长,对用户的体验感不好。
所以12306服务是在启动的时候都已经创建好一堆线程。调用pthread_cond_wait让这些
线程休眠,当有客户端请求买票的时候,只需要唤醒这些休眠的线程即可,有于省去了
创建线程的时候,所以这种方式的效率非常的高。
- #include
- #include
- #include
- #define ERROR(msg) do{\
- printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
- printf(msg);\
- exit(-1); \
- }while(0)
-
- pthread_cond_t cond;
- pthread_mutex_t lock;
- int i = 0;
-
- void* task1(void* argc)
- {
- while (1){
- pthread_mutex_lock(&lock);
- while(i != 0){
- pthread_cond_wait(&cond,&lock);
- }
- printf("我生产了一辆汽车\n");
- i = 1;
- pthread_cond_signal(&cond);
- pthread_mutex_unlock(&lock);
- }
- }
-
- void* task2(void* argc)
- {
- while (1){
- pthread_mutex_lock(&lock);
- while(i == 0){
- pthread_cond_wait(&cond,&lock);
- }
- printf("我买了一辆汽车\n");
- i = 0;
- pthread_cond_signal(&cond);
- pthread_mutex_unlock(&lock);
- }
- }
-
- int main(int argc, char const *argv[])
- {
- pthread_t pid1, pid2;
- pthread_mutex_init(&lock, NULL);
- pthread_cond_init(&cond, NULL);
-
- if (pthread_create(&pid1, NULL, task1, NULL)){
- ERROR("create error");
- }
-
- if(pthread_create(&pid2, NULL, task2, NULL)){
- ERROR("create error");
- }
-
- pthread_join(pid1, NULL);
- pthread_join(pid2, NULL);
-
- pthread_cond_destroy(&cond);
- pthread_mutex_destroy(&lock);
- return 0;
- }
如果用if的话,假如是一号线程先抢到这个锁,然后生产了一辆汽车,然后唤醒了一个线程,因为此时还没有线程,然后释放锁,这个时候如果是二号进程抢到锁,那用if和while都一样,但是如果还是一号线程抢到这个锁,然后进入if i!= 0,然后由于上次唤醒的一个线程还没有用,所以此时立马唤醒,然后又生产了一辆车,这个时候就出现问题了,但是如果用while就不会,因为此时,必须得二号进程,把i == 0,这个才能往下走,不然一号进程一直在那个while循环里面。