7. 线程同步
线程同步:协调步骤,顺序执行
7.1 互斥量
7.1.1 销毁并初始化一个锁pthread_mutex_init()
包含头文件:
#include <pthread.h>
函数原型:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
参数 | 说明 |
---|---|
restrict | 约束该块内存区域对应的数据,只能通过后面的变量进行访问和修改 |
mutex | 互斥量(锁) |
attr | 互斥量的属性,可以不考虑,NULL |
7.1.2 给共享资源加锁pthread_mutex_lock()
包含头文件:
#include <pthread.h>
函数原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
函数说明:
- 如果当前为锁,成功,该线程加锁
- 如果当前已锁,阻塞等待
参数 | 说明 |
---|---|
mutex | 互斥量 |
return | 成功:0 失败:errno,立即返回 |
7.1.3 pthread_mutex_trylock()
包含头文件:
#include <pthread.h>
函数原型:
int pthread_mutex_trylock(pthread_mutex_t *mutex);
函数说明:
- 如果当前为锁,成功,该线程加锁
- 如果当前已锁,立即返回
参数 | 说明 |
---|---|
mutex | 互斥量 |
return | 成功:0 失败:errno,立即返回 |
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
pthread_mutex_t mutex;
void *thr(void *arg)
{
while(1)
{
pthread_mutex_trylock(&mutex);
printf("hello world\n");
sleep(30);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main()
{
pthread_mutex_init(&mutex,NULL);
pthread_t tid;
pthread_create(&tid, NULL, thr, NULL);
sleep(1);
while(1)
{
int ret = pthread_mutex_trylock(&mutex);
if(ret > 0)
{
printf("ret = %d, sttmsg = %s\n", ret, strerror(ret));
sleep(1);
}
}
return 0;
}
运行结果:
7.1.4 给共享资源解锁pthread_mutex_unlock()
包含头文件:
#include <pthread.h>
函数原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
函数说明:
- 如果当前为锁,成功,该线程解锁
参数 | 说明 |
---|---|
mutex | 互斥量 |
return | 成功:0 失败:errno |
7.1.5 销毁一个锁pthread_mutex_destroy()
包含头文件:
#include <pthread.h>
函数原型:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数 | 说明 |
---|---|
mutex | 传入的锁 |
return | 成功:0 失败:errno |
7.1.6 常量初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
未添加锁打印:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
void *thr1(void *arg)
{
while(1)
{
printf("hello");
sleep(rand()%3);
printf("world\n");
sleep(rand()%3);
}
}
void *thr2(void *arg)
{
while(1)
{
printf("HELLO");
sleep(rand()%3);
printf("WORLD\n");
sleep(rand()%3);
}
}
int main()
{
srand((unsigned)time(NULL));
pthread_t tid[2];
pthread_create(&tid[0], NULL, thr1, NULL);
pthread_create(&tid[1], NULL, thr2, NULL);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
运行结果:
添加锁打印:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thr1(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
printf("hello");
sleep(rand()%3);
printf("world\n");
pthread_mutex_unlock(&mutex);
sleep(rand()%3);
}
}
void *thr2(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
printf("HELLO");
sleep(rand()%3);
printf("WORLD\n");
pthread_mutex_unlock(&mutex);
sleep(rand()%3);
}
}
int main()
{
srand((unsigned)time(NULL));
pthread_t tid[2];
pthread_create(&tid[0], NULL, thr1, NULL);
pthread_create(&tid[1], NULL, thr2, NULL);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
运行结果:
7.2 读写锁
特点:读共享、写独占、写优先级高
读写锁仍然是一把锁,有不同的状态
- 未加锁
- 读锁
- 写锁
7.2.1 初始化读写锁pthread_rwlock_init()
函数原型:
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
初始化常量:
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
7.2.2 销毁读写锁pthread_rwlock_destroy()
函数原型:
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
7.2.3 加读锁
函数原型:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
7.2.4 加写锁
函数原型:
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
7.2.5 释放锁pthread_rwlock_unlock()
函数原型:
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
读写示例:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
int begin_num = 1000;
void *thr_write(void* arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);
printf("write thread:%lu %d\n", pthread_self(), ++begin_num);
sleep(1);
pthread_rwlock_unlock(&rwlock);
sleep(2);
}
return NULL;
}
void *thr_read(void* arg)
{
while(1)
{
pthread_rwlock_rdlock(&rwlock);
printf("read thread:%lu %d\n", pthread_self(), begin_num);
sleep(1);
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
return NULL;
}
int main()
{
int n = 8, i = 0;
pthread_t tid[8];
for (i = 0;i < 5;i++)
{
pthread_create(&tid[i], NULL, thr_read, NULL);
}
for (;i < 8;++i)
{
pthread_create(&tid[i], NULL ,thr_write, NULL);
}
for(i = 0;i < 8;i++)
{
pthread_join(tid[i], NULL);
}
return 0;
}
运行结果:
7.3 条件变量
条件变量:可以引起阻塞,并非锁
7.3.1 初始化条件
函数原型:
int pthread_cond_init(pthread_cond_t *cond);
初始化变量:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
7.3.2 销毁条件变量
函数原型:
int pthread_cond_destroy(pthread_cond_t *cond);
7.3.3 等待条件
函数原型:
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
函数说明:
pthread_cond_timedwait
:超时等待pthread_cond_wait
:阻塞等待- 条件变量不是锁需要和互斥量组合使用
- 先释放
mutex
- 阻塞在
cond
上
7.3.4 唤醒线程
7.3.4.1 唤醒至少一个阻塞在cond上线程
函数原型:
int pthread_cond_signal(pthread_cond_t *cond);
7.2.4.2 唤醒阻塞在条件cond上的全部线程
函数原型:
int pthread_cond_broadcast(pthread_cond_t *cond);
示例代码(生产者、消费者模型):
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int begin_num = 1000;
typedef struct _ProdInfo
{
int num;
struct _prodInfo *next;
}ProdInfo;
ProdInfo *Head = NULL;
void *thr_producer(void *arg)
{
while(1)
{
ProdInfo *prod = malloc(sizeof(ProdInfo));
prod->num = begin_num++;
printf("%s-self=%lu-%d\n", "producer", pthread_self(), prod->num);
pthread_mutex_lock(&mutex);
prod->next = Head;
Head = prod;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
sleep(1);
}
return NULL;
}
void *thr_customer(void *arg)
{
ProdInfo * prod = NULL;
while(1)
{
pthread_mutex_lock(&mutex);
while(Head == NULL)
{
pthread_cond_wait(&cond, &mutex); // 再此之前必须先加锁
}
prod = Head;
Head = Head->next;
printf("%s-self=%lu-%d\n", "customer", pthread_self(), prod->num);
pthread_mutex_unlock(&mutex);
free(prod);
prod = NULL;
sleep(2);
}
return NULL;
}
int main()
{
pthread_t tid[3];
pthread_create(&tid[0], NULL, thr_producer, NULL);
pthread_create(&tid[1], NULL, thr_customer, NULL);
pthread_create(&tid[2], NULL, thr_customer, NULL);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_join(tid[2], NULL);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
运行结果:
7.4 信号量
7.4.1 初始化信号量sem_init()
包含头文件:
#include <semaphore.h>
函数原型:
int sem_init(sem_t *sem, int pshared, unsigned int value);
函数说明:
sem
:信号量pshared
:取0用于线程间;非0(一般为1)用于进程间value
:信号量初始值
7.4.2 销毁信号量sem_destroy()
包含头文件:
#include <semaphore.h>
函数原型:
int sem_destroy(sem_t *sem);
7.4.3 释放信号量sem_post()
包含头文件:
#include <semaphore.h>
函数原型:
int sem_post(sem_t *sem);
函数说明:
释放成功:
value++
7.4.4 申请信号量
包含头文件:
#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);
函数说明:
申请成功,
value--
生产者消费者模型:
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#define _SEM_CNT_ 5
sem_t blank, xfull;
int queue[_SEM_CNT_];
int begin_num = 100;
void *thr_producer(void *arg)
{
int i = 0;
while(1)
{
sem_wait(&blank);
printf("producer:self=%lu:%d\n", pthread_self(),begin_num);
queue[(i++)%_SEM_CNT_] = begin_num++;
sem_post(&xfull);
sleep(rand()%3);
}
return NULL;
}
void *thr_customer(void *arg)
{
int i = 0, num;
while(1)
{
sem_wait(&xfull);
num = queue[(i++) % _SEM_CNT_];
printf("customer:self=%lu:%d\n", pthread_self(),num);
sem_post(&blank);
sleep(rand()%3);
}
return NULL;
}
int main()
{
sem_init(&blank, 0, _SEM_CNT_);
sem_init(&xfull, 0, 0);
pthread_t tid[2];
pthread_create(&tid[0], NULL, thr_producer, NULL);
pthread_create(&tid[1], NULL, thr_customer, NULL);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
sem_destroy(&blank);
sem_destroy(&xfull);
return 0;
}
运行结果:
7.5 文件锁
struct flock {
...
short l_type; /* 锁类型: F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /* 位置: SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* 锁的起始位置 */
off_t l_len; /* 锁定的字节数 */
pid_t l_pid; /* 由F_GETLK和F_OFD_GETLK设置 */
...
};
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
int fd = open(argv[1], O_RDWR | O_CREAT, 0666);
if(fd < 0)
{
perror("open err");
return -1;
}
struct flock lk;
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
lk.l_start = 0;
lk.l_len = 0;
if(fcntl(fd, F_SETLK, &lk) < 0)
{
perror("get lock err");
exit(-2);
}
while(1)
{
printf("***\n");
sleep(1);
}
return 0;
}