一、可重入函数的使用
线程函数尽量保持可重入性,不可重入函数会造成的临界资源访问的问题;
如:
/* 不可重入函数造成的临界资源访问问题 */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int count = 0;
// 声明一个mutex锁类型
pthread_mutex_t mutex;
void* doit(void* arg)
{
int val, i;
for(i = 0;i < 5000;i++)
{
// 加锁
pthread_mutex_lock(&mutex);
val = count;
val++;
printf("val = %d\n", val);
count = val;
// 解锁
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main(void)
{
int res;
pthread_t tid, cid;
// 初始化mutex锁类型
pthread_mutex_init(&mutex, NULL);
// 创建两个新的线程
pthread_create(&tid, NULL, doit, NULL);
pthread_create(&cid, NULL, doit, NULL);
// 等待线程的汇合
pthread_join(tid, NULL);
pthread_join(cid, NULL);
// 销毁mutex锁类型
pthread_mutex_destroy(&mutex);
return 0;
}
二、线程的同步
2.1 mutex锁
当一个线程需要使用临界资源时,线程会对该资源加锁,待使用完毕后,才解锁该资源。
mutex锁的类型是:pthread_mutex_t
typedef union
{
struct __pthread_mutex_s
{
int __lock;
unsigned int __count;
int __owner;
unsigned int __nusers;
int __kind;
short __spins;
short __elision;
__pthread_list_t __list;
} __data;
char __size[40];
long int __align;
} pthread_mutex_t;
mutex锁的静态初始化
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
(1)pthread_mutex_init(3)
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t, *mutexattr);
功能:
主要用于初始化一个mutex锁;
参数:
第一个参数:指定要初始化的mutex锁;
第二个参数:指定初始化mutex锁的属性,给NULL表示缺省属性;
返回值:
总是返回0;
(2)pthread_mutex_lock(3)
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:
主要用于将指定的mutex设置为lock状态,实现加锁效果。如果mutex之前处于unlocked状态,立即加锁,并返回;如果mutex之前处于locked状态,则挂起等待mutex变为unlocked状态后再加锁。
参数:
第一个参数:指定要设置为locked状态的mutex锁;
返回值:
success —- 0,error —- 非0;
(3)pthread_mutex_trylock(3)
#include <pthread.h>
int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:
主要用于将指定的mutex设置为lock状态,实现加锁效果。如果mutex之前处于unlocked状态,立即加锁,并返回;如果mutex之前处于locked状态,立即返回错误,并设置errno为EBUSY。
参数:
mutex:指定要设置为locked状态的mutex锁;
返回值:
success —- 0,error —- 非0;
(4)pthread_mutex_unlock(3)
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:
主要用于将指定的mutex锁设置为unlocked状态,实现解锁效果。
参数:
第一个参数:指定要解开的mutex锁;
返回值:
success —- 0,error —- 非0;
(5)pthread_mutex_destroy(3)
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:
主要用于销毁指定的mutex锁;
参数:
第一个参数:指定要销毁的mutex锁;
返回值:
success —- 0,error —- 非0;
注意:
以上这些函数都是对pthread_mutex_t类型变量的操作。使用时一定要注意锁的范围,即使用到临界资源的时候,加锁;不使用临界资源的时候解锁。
2.2 条件变量
线程间同步的一种情况,有两个线程A和B。线程A需要等某个条件成立的时候,才能继续往下执行,这时候,条件不成立,线程A阻塞等待。线程B的执行使这个条件变为成立。线程A得知条件成立了,线程A继续往下执行。这样的清况称为条件变量。
条件变量的类型是:pthread_cond_t
typedef union
{
struct
{
int __lock;
unsigned int __futex;
__extension__ unsigned long long int __total_seq;
__extension__ unsigned long long int __wakeup_seq;
__extension__ unsigned long long int __woken_seq;
void *__mutex;
unsigned int __nwaiters;
unsigned int __broadcast_seq;
} __data;
char __size[48];
__extension__ long long int __align;
} pthread_cond_t;
条件变量的静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
(1)pthread_cont_init(3)
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
功能:
主要用于初始化指定的条件变量;
参数:
第一个参数:结构体类型的指针,存放要初始化的条件变量;
第二个参数:结构体类型的指针,指定条件变量的属性,默认给NULL;
typedef union
{
char __size[4];
int __align;
} pthread_condattr_t;
返回值:
success —- 0,error —- 非0;
(2)pthread_cond_signal(3)
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
功能:
启动一个线程,等待条件变量为真的线程;
参数:
第一个参数:指定条件变量。在这个条件变量上等待的一个线程;
返回值:
success —- 0,error —- 非0;
(3)pthread_cond_broadcast(3)
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);
功能:
启动所有的线程,这些线程是等待条件变量为真的所有的线程;
参数:
第一个参数:指定了条件变量,在这个条件变量上等待的所有线程;
返回值:
success —- 0,error —- 非0;
(4)pthread_cond_wait(3)
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
功能:
当条件变量不为真时,解开指定的mutex锁;等待至条件变量为真时,再给mutex加锁。
参数:
第一个参数:指定要等待的条件变量;
第二个参数:指定一个mutex锁;
返回值:
success —- 0,error —- 非0;
(5)pthread_cond_timedwait(3)
#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
功能:
在指定时间内等待。超时返回错误。其他同上个函数。
参数:
第一个参数:指定要等待的条件变量;
第二个参数:指定一个mutex锁;
第三个参数:指定了要等待的时间;
struct timespec
{
__time_t tv_sec; //__time_t = long int; 秒
__syscall_slong_t tv_nsec; //__syscall_slong_t = long int; 纳秒
};
返回值:
success —- 0,error —- 非0;
(6)pthread_cond_destroy(3)
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
功能:
主要用于销毁指定的条件变量;
参数:
第一个参数:指定要销毁的条件变量;
返回值:
success —- 0,error —- 非0;
线程的实现:LinuxThreads:2.4、NPTL:2.6
LFS(Linux from Scratch)是一种从网上直接下载源码,从头编译LINUX的安装方式。
2.3 信号量
信号量是指有多个相同的资源,多个线程竞争多个资源。在可用资源数减为0的情况下,线程等待。线程获取一个资源,可用资源数减1.当线程释放一个资源的时候,可用资源数加1。既能应用于多线程,又能应用于多进程。
信号量的类型是:sem_t
typedef union
{
char __size[32];
long int __align;
} sem_t;
(1)sem_init(3)
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
/* Link with -pthread. */
功能:
初始化一个匿名的信号量;
参数:
第一个参数:指定要初始化的信号量变量的地址;
第二个参数:0 —- 多线程、非0 —- 多进程
第三个参数:指定了信号量的初始化,信号量提供的资源数;
(2)sem_destroy(3)
#include <semaphore.h>
int sem_destroy(sem_t *sem);
/* Link with -pthread. */
功能:
主要用于销毁一个指定的匿名信号量;
参数:
第一个参数:指定要销毁的信号量;
(3) sem_post(3)
#include <semaphore.h>
int sem_post(sem_t *sem);
/* Link with -pthread. */
功能:
主要用于解锁一个指定的信号量;
参数:
第一个参数:指定要解锁的信号量。如果信号量可用资源数大于0,调用sem_wait等待的进程或线程这时候,被唤醒。
信号量的解锁是什么意思???
increments信号量的值增加,可用资源数+1
(4)sem_wait(3)
#include <semaphore.h>
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
/* Link with -pthread. */
功能:
主要用于锁定一个指定的信号量,此时信号量的可用资源数减1;
参数:
第一个参数:指定要锁定的信号量。如果可用资源数大于0,立即返回。否则阻塞等待信号量的值大于0;