多线程在一个进程中有多个控制权,也会有多个函数同时运行,执行各自的CPU指令,就算单CPU,也可以通过线程间指令切换,达到多线程同时运行的效果
并发情况,不同线程之间指令无法确定执行先后顺序,假如这个顺序对运行结果造成影响,那么就会出现竞争,而且会出现问题,要解决竞争可以将原本分离的不同线程间的指令修改成原子操作,那么竞争自然就不存在了
多线程由于可以共享资源,因此同步问题必须要解决,在一定时间区间内只能某一个线程访问某一个资源,需要通过一些方法同步资源
下面是一个随手造的例子:
本来主线程和子线程分别对全局变量i进行减操作,但是要求 i 为正数才能减,也就是不管主线程还是子线程,先执行的一方,能减,操作之后 i=0,而接着另一方的if判断为假,就不会再减法操作,最终 i 的值为0;可这里我对于两个线程的减法之前做了一个sleep 1秒,这样能够保证两个线程在if判断的时候都为真,因为来不及减1,这样最终会减两次1,i 的值会变成我们不想得到的-1,这样就很明显暴露了线程同步的问题
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> int i = 1; void *thread_function(){ if (i > 0){ sleep(1); --i; } pthread_exit("See you, lihui"); } int main(){ pthread_t child; if (pthread_create(&child, NULL, thread_function, NULL)){ printf("Create new thread failed!\n"); exit(1); } if (i > 0){ sleep(1); --i; } pthread_join(child, NULL); printf("i = %d\n", i); return 0; }
编译执行一把:
lihui@2015 ~ $ ./a.exe i = -1
互斥量同步
通过使用pthread的互斥接口保护数据,确保同一时间只有一个线程来访问数据;互斥量mutex本质上也就是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成之后释放互斥量上的锁;对互斥量加锁之后,任何其它试图再次对互斥量加锁的线程将会被阻塞,直到当前线程释放掉该互斥锁
如果释放互斥锁的时候有多个线程阻塞了,所有在该互斥锁上的阻塞线程都会变成可运行状态,第一个变成运行状态的线程可以对互斥锁加锁,其他线程将会看到互斥锁依旧被锁住了,继续阻塞,继续等着变成没锁可用,这样,每次就只有一个线程可以执行
互斥变量用pthread_mutex_t数据类型来表示,在使用之前必须进行初始化,只对静态分配的互斥量可以将它设置为常量PTHREAD_MUTEX_INITIALIZER,也可以调用pthread_mutex_init函数来进行初始化;如果是动态分配互斥量(malloc),那么在释放之前需要调用pthread_mutex_destroy
#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); int pthread_mutex_destroy(pthread_mutex_t *mutex);
他们都是成功就返回0,失败就返回错误码;如果互斥量用默认属性,attr设置为NULL
对互斥量加锁,调用pthread_mutex_lock,如果互斥量已经上锁,调用线程将阻塞直到互斥量被解锁;对互斥量解锁,调用pthread_mutex_unlock;如果不希望被阻塞,调用pthread_mutex_trylock尝试对互斥量进行加锁,假如此时互斥量处于未锁住状态,那么pthread_mutex_trylock将锁住互斥量,不会出现阻塞并返回0,否则此时互斥量如果已经锁住状态,pthread_mutex_trylock将会失败,不能锁住互斥量
#include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlick(pthread_mutex_t *mutex);
同样成功返回0,失败返回错误编号
因此,有了锁之后,信心满满,由于主线程和子线程最关键的就在于if判断是否为真,判断的结果依赖于对方的减减操作,因此我直接在两个if的前后加上锁和解锁:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> int i = 1; pthread_mutex_t mutex; void *thread_function(){ pthread_mutex_lock(&mutex); if (i > 0){ sleep(1); --i; } pthread_mutex_unlock(&mutex); pthread_exit("See you, lihui"); } int main(){ pthread_t child; if (pthread_create(&child, NULL, thread_function, NULL)){ printf("Create new thread failed!\n"); exit(1); } pthread_mutex_lock(&mutex); if (i > 0){ sleep(1); --i; } pthread_mutex_unlock(&mutex); pthread_join(child, NULL); printf("i = %d\n", i); return 0; }
同一个互斥量加锁,但是出人意料的是结果:
lihui@2015 ~ $ ./a.exe i = -1
这就神了,让我今晚不要睡觉的节奏??