线程是进程的一条执行路径,在UNIX中,线程是轻量级的进程。这点与windows不同。典型的UNIX进程可以看成只有一个主线程: 一个进程在某一时刻只能做一件事。
有了多线程之后,我们可以让一个进程同一时刻做不止一件事,每个线程处理各自独立的任务。
1.创建的方式不相同,多进程调用vfork()/fork()进行创建而多线程是调用pthread_create()创建。
2.进程是创建多个子进程空间和内存都独立。多个线程是在一个进程的情况下完成多个任务,并且进程定义的全局变量,所属的所有线程都可以对它进行修改。
3.由于调用了pthread_create通常还需要在编译时调用pthread动态库。
1.在创建之前可以先用man查看pthread_create()细节
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
2.线程的创建并不能保证哪个线程会先运行
3.在编译时,一定要调用系统自带的pthread动态库(-lpthread)
4.如果创建失败,其多线程会返回一个错误码,并且是小于0的值。
由于线程调度的顺序由系统来决定,因此,全局变量g_judge的调用赋值变化是不稳定的,换个意思是:A和B都同样调用g_judge这个全局变量,那么如果在A调用g_judge的同时B也在对g_judge调用,导致其值变化不按人们所想的值去变化。为了解决这个问题要求同一时间只允许一个线程访问改变量,所以引入锁,对数据进行保护。
可以使用pthread的互斥借口来保护数据,确保同一时间只有一个线程访问数据。
互斥量使用pthread_mutex_t数据类型来表示。
在使用之前,要对其进行初始化:
PTHREAD_MUTEX_INITIALIZER(静态分配的互斥量)或pthread_mutex_init函数进行初始化。
pthread_mutex_t lock;
int pthread_mutex_init(pthread_mutex *restrict mutex, const pthread_mutexattr_t *restrict atrr);
int pthread_mutext_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex); // 阻塞
int pthread_mutex_trylock(pthread_mutex_t *mutex); // 非阻塞
int pthread_mutex_unlock(pthread_mutex_t *mutex); // 释放锁
如果线程试图尝试对同一个互斥量加锁两次,那么它自身会陷入死索的状态,以及其他不太明显的方式也能产生死锁。
临界资源:所有程序都可调用的资源
临界区:临界资源存放的位置
如何解决死锁:通过仔细控制互斥量加锁的顺序(按顺序加锁)
分别对workers1、workers2、workers3进行加锁其中,workers3对其进行上锁2次,进行死锁测试。
workers1:
workers2:
workers3:
程序运行到workers3时,程序不在运行,证明了死锁的原因之一是重复上锁,导致解锁失败。
如果屏蔽多余的上所步骤:
保证了数据的规律性。