学习内容
线程的取消
线程和信号,与多进程的信号有不同
线程安全,一切麻烦从共享资源开始
线程同步,各种锁的使用
线程取消
int pthread_cancel(pthread_t thread);
// 本程序演示线程的取消。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int var=0;
void *thmain(void *arg); // 线程主函数。
int main(int argc,char *argv[])
{
pthread_t thid;
// 创建线程。
if (pthread_create(&thid,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
usleep(100); pthread_cancel(thid);
int result=0;
void *ret;
printf("join...\n");
result=pthread_join(thid,&ret); printf("thid result=%d,ret=%ld\n",result,ret);
printf("join ok.\n");
printf("var=%d\n",var);
}
void *thmain(void *arg) // 线程主函数。
{
// pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
for (var=0;var<400000000;var++)
{
;
pthread_testcancel();
}
return (void *) 1;
}
线程和信号
进程和信号 and 线程和信号的区别:
线程安全
什么是可重入函数?
可重入的函数简单来说就是可以被中断的函数
一文理解可重入函数
什么是原子性?
什么是可见性?
什么是顺序性?
volatile关键字?
volatile不是原子的。
如何解决线程安全?
原子操作只支持整数。支持对象要用线程同步
线程同步,各种锁的使用
互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
互斥锁的demo:
#include <pthread.h>
pthread_mutex_t mutex;
int max = 0;
void* arg_main1(void* arg) {
for(int i = 0;i < 100; i++) {
pthread_mutex_init(&mutex,NULL);
max += 1;
printf("arg_main1 max = %d \n",max);
//sleep(1);
pthread_mutex_unlock(&mutex);
}
}
void* arg_main2(void* arg) {
for(int i = 0;i < 100; i++) {
pthread_mutex_init(&mutex,NULL);
max += 1;
printf("arg_main2 max = %d \n",max);
//sleep(1);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_mutex_init(&mutex,NULL);
pthread_t pid1,pid2;
pthread_create(&pid1,NULL,&arg_main1,NULL);
pthread_create(&pid2,NULL,&arg_main2,NULL);
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
printf("max = %d \n",max);
pthread_mutex_destroy(&mutex);
return 0;
}
锁的属性
互斥锁和自旋锁的区别?
互斥锁不消耗cpu,线程会休眠,而自旋锁会消耗cpu,它用cpu使用
使用自旋锁假设等待时间很短。
等待时间短使用自旋锁,等待时间长使用互斥锁。
pthread_mutex_init和pthread_spin_init 第二个参数不同,mutex是属性,spin是一个标志。
加锁解锁时候也不同:一个要两个参数,一个要一个参数。
自旋锁
api如下:
int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
PTHREAD_PROCESS_PRIVATE 能否共享自旋锁? 一般填私有的。
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
自旋锁使用demo:
#include <pthread.h>
pthread_spinlock_t mutex;// 定义自旋锁
int max = 0;
void* arg_main1(void* arg) {
for(int i = 0;i < 100; i++) {
pthread_spin_lock(&mutex);
max += 1;
printf("arg_main1 max = %d \n",max);
usleep(1);
pthread_spin_unlock(&mutex);
}
}
void* arg_main2(void* arg) {
for(int i = 0;i < 100; i++) {
pthread_spin_lock(&mutex);
max += 1;
printf("arg_main2 max = %d \n",max);
usleep(2);
pthread_spin_unlock(&mutex);
}
}
int main()
{
pthread_spin_init(&mutex,PTHREAD_PROCESS_PRIVATE);
pthread_t pid1,pid2;
pthread_create(&pid1,NULL,&arg_main1,NULL);
pthread_create(&pid2,NULL,&arg_main2,NULL);
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
printf("max = %d \n",max);
pthread_spin_destroy(&mutex);
return 0;
}
读写锁
api:
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock);// 读锁
int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock);// 写锁
int pthread_rwlock_unlock(pthread_rwlock_t *__rwlock);// 解锁
- 读写锁支持高并发
- 读写锁有三种状态:读模式加锁,写模式加锁和不加锁。
读写锁的特点
读写锁注意点
读写锁和互斥锁的区别?
- 读写锁有三种状态。互斥锁只有两种。
读写锁demo:
// 本程序演示线程同步-读写锁。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER; // 声明读写锁并初始化。
void *thmain(void *arg); // 线程主函数。
void handle(int sig); // 信号15的处理函数。
int main(int argc,char *argv[])
{
signal(15,handle); // 设置信号15的处理函数。
pthread_t thid1,thid2,thid3;
// 创建线程。
if (pthread_create(&thid1,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
sleep(1);
if (pthread_create(&thid2,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
sleep(1);
if (pthread_create(&thid3,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
// 等待子线程退出。
pthread_join(thid1,NULL); pthread_join(thid2,NULL); pthread_join(thid3,NULL);
pthread_rwlock_destroy(&rwlock); // 销毁锁。
}
void *thmain(void *arg) // 线程主函数。
{
for (int ii=0;ii<100;ii++)
{
printf("线程%lu开始申请读锁...\n",pthread_self());
pthread_rwlock_rdlock(&rwlock); // 加锁。
printf("线程%lu开始申请读锁成功。\n\n",pthread_self());
sleep(5);
pthread_rwlock_unlock(&rwlock); // 解锁。
printf("线程%lu已释放读锁。\n\n",pthread_self());
if (ii==3) sleep(8);
}
}
void handle(int sig) // 信号15的处理函数。
{
printf("开始申请写锁...\n");
pthread_rwlock_wrlock(&rwlock); // 加锁。
printf("申请写锁成功。\n\n");
sleep(10);
pthread_rwlock_unlock(&rwlock); // 解锁。
printf("写锁已释放。\n\n");
}
条件变量
- 条件变量和互斥锁一起使用。实现生产者消费者模型,还可以通知功能。
api:
pthread_cond_t cond;// 定义条件变量
int pthread_cond_wait(pthread_cond_t *__restrict__ __cond, pthread_mutex_t *__restrict__ __mutex)
int pthread_cond_signal(pthread_cond_t *__cond)
int pthread_cond_destroy(pthread_cond_t *__cond)
demo:
pthread_cond_t cond;// 定义条件变量
pthread_mutex_t mutex;
int max = 0;
void* arg_main1(void* arg) {
while(1) {
printf("线程%lu开始等待条件信号...\n",pthread_self());
pthread_cond_wait(&cond,&mutex); // 等待条件信号。
printf("线程%lu等待条件信号成功。\n\n",pthread_self());
}
}
void func(int sig) {
printf("发送条件信号...\n");
pthread_cond_signal(&cond);
}
int main()
{
signal(15,func);
pthread_cond_init(&cond,NULL);
pthread_mutex_init(&mutex,NULL);
pthread_t pid1,pid2;
pthread_create(&pid1,NULL,&arg_main1,NULL);
pthread_create(&pid2,NULL,&arg_main1,NULL);
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
信号量
线程的信号量不能用在进程中。
api
// 本程序演示线程同步-信号量。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
int var;
sem_t sem; // 声明信号量。
void *thmain(void *arg); // 线程主函数。
int main(int argc,char *argv[])
{
sem_init(&sem,0,1); // 初始化信号量。
pthread_t thid1,thid2;
// 创建线程。
if (pthread_create(&thid1,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
if (pthread_create(&thid2,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
// 等待子线程退出。
printf("join...\n");
pthread_join(thid1,NULL);
pthread_join(thid2,NULL);
printf("join ok.\n");
printf("var=%d\n",var);
sem_destroy(&sem); // 销毁信号量。
}
void *thmain(void *arg) // 线程主函数。
{
for (int ii=0;ii<1000000;ii++)
{
sem_wait(&sem); // 加锁。
var++;
sem_post(&sem); // 解锁。
}
}