多线程
线程函数
以下函数包含在头文件 pthread.h
中
线程ID
每一个线程都有一个唯一的线程ID,ID类型为pthread_t,是一个无符号长整形数,这个函数用于返回线程ID
pthread_t pthread_self(void);
- 返回值:当前线程ID
创建线程
int pthread_create(pthread_t * thread, const pthread_attr_t* attr, void * (*start_routine)(void*), void* arg);
thread
:传出参数,线程创建成功后会将线程id写入这个指针指向的内存attr
:线程属性,一般情况下默认即可,写NULLstart_routine
:函数指针,该函数会在子线程中执行,类似于子线程的main函数,要求函数是静态函数arg
:start_routine
指向的函数的参数- 返回值:创建成功返回0,失败则返回对应错误号
线程退出
这个函数用于线程的退出,但是不会释放地址空间,只要调用该函数线程立刻退出,不会影响其他线程的运行
void pthread_exit(void *retval);
retval
:线程退出时携带的数据,当前子线程的主线程会得到该数据,不需要使用写NULL即可
线程回收
这个函数是阻塞函数,如果还有子线程在运行,调用该函数就会阻塞,子线程退出函数解除阻塞进行资源的回收,所以完整的线程关闭即要子线程自己退出,也要主线程来回收子线程资源
该函数被调用一次,只能回收一个子线程,如果有多个子线程则需要循环进行回收
int pthread_join(pthread_t thread, void **retval);
thread
:要回收的线程的IDretval
:传出参数,指向一级指针,一级指针指向一块内存,内存中存储了pthread_exit()
传出的数据。不需要写NULL即可
线程脱离
将线程设置成脱离态(detached)后,当这一线程运行结束时,它的资源会被系统自动回收,而不再需要在其它线程中对其进行 pthread_join() 操作
int pthread_detach(pthread_t thread);
互斥锁
多用于线程同步中
设想这样一种情况,我们创建了两个线程,他们的任务就是把变量i
从0加到100,线程A把变量i
从3加到了4,还没来得及把数据写回物理内存,CPU时间片就被线程B抢走了,线程B从物理内存里取出的变量i
还没被线程A更新,这就导致线程A白数了一次,降低了效率。
这种情况不仅会降低效率,有时甚至会引发数据混乱,造成错误。
我们不希望这种情况发生,即不希望多个线程同时操作一个资源,我们就可以用到互斥锁。
以下函数包含在头文件 pthread.h
中
创建一把互斥锁
pthread_mutex_t mutex;
在创建的锁对象中保存了当前这把锁的状态信息:锁定还是打开,如果是锁定状态还记录了给这把锁加锁的线程ID
初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
mutex
:需要初始化的互斥锁attr
:互斥锁的属性,一般设置为NULL即可
上锁和解锁
- 上锁(阻塞)
当锁不空闲,调用这个函数的线程就会挂起等待,直到自己抢到了锁并上锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
- 上锁(非阻塞)
当锁不空闲,这个函数会直接返回EBUSY,如果锁空闲,那么自己就加锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
- 解锁
由抢到了锁并上锁的线程来调用,把锁解开
int pthread_mutex_unlock(pthread_mutex_t *mutex);
释放互斥锁资源
int pthread_mutex_destroy(pthread_mutex_t *mutex);
信号量
多用于线程同步中
信号量类型是sem_t
sem_t sem;
初始化信号量
int sem_init (sem_t *sem, int pshared, unsigned int value);
参数一是要被初始化的信号量,后两个参数不用关心,填0
信号量加一
int sem_post(sem_t * sem);
将信号量加一
信号量减一
int sem_wait(sem_t * sem);
当信号量大于0时,将信号量减一,当信号量等于0时,将调用此函数的线程阻塞,直到信号量大于0,并将信号量减一
反正就是横竖都要把信号量减一
销毁信号量
int sem_destroy(sem_t *sem);