线程同步介绍
一、竞态条件和锁二、互斥锁——pthread_mutex_t1、定义2、测试例程#includestdio.h #includestdlib.h #includeunistd.h #includepthread.h #define THREAD_COUNT 20000 //初始化锁 static pthread_mutex_t counter_mutexPTHREAD_MUTEX_INITIALIZER; //需要创建的多个线程 void *add_thread(void *arg) { //转换传入参数 int *p (int *)arg; //在累加之前获取锁保证同一时间只有一个线程对其累加 pthread_mutex_lock(counter_mutex); (*p); //累加完之后 释放锁 pthread_mutex_unlock(counter_mutex); return (void *)0; } int main(int argc, char const *argv[]) { pthread_t pid[THREAD_COUNT]; int num 0; for (int i 0; i THREAD_COUNT; i) { //创建的线程功能是传入的参数累加1 pthread_create(pidi,NULL,add_thread,num); } //等待所有线程执行完成 for (int i 0; i THREAD_COUNT; i) { pthread_join(pid[i],NULL); } //打印最终的累加结果 printf(累加结果是%d\n,num); return 0; }makefilerace_condition_test:race_condition_test.c -$(CC) -o $ $^ -lpthread -./$ -rm ./$三、读写锁1、定义2、测试例程1没有加写锁的情况#includestdio.h #includepthread.h #includeunistd.h static pthread_rwlock_t rwlock PTHREAD_RWLOCK_INITIALIZER; int shared_data0; void *lock_writer(void *arg) { int temp shared_data 1; sleep(1); shared_data temp; printf(当前是%s,shared_data为%d\n,(char*)arg,shared_data); } void *lock_read(void *arg) { //读写锁中的读是可以由多个线程统一读取的 //获取读锁 pthread_rwlock_rdlock(rwlock); printf(当前是%s,shared_data为%d\n,(char*)arg,shared_data); pthread_rwlock_unlock(rwlock); } int main(int argc, char const *argv[]) { //显示初始化读写锁 pthread_rwlock_init(rwlock,NULL); pthread_t writer1,writer2,reader1,reader2,reader3,reader4,reader5,reader6; //创建两个写线程 pthread_create(writer1,NULL,lock_writer,writer1); pthread_create(writer2,NULL,lock_writer,writer2); //休眠等待 sleep(3); //创建读线程 pthread_create(reader1,NULL,lock_read,reader1); pthread_create(reader2,NULL,lock_read,reader2); pthread_create(reader3,NULL,lock_read,reader3); pthread_create(reader4,NULL,lock_read,reader4); pthread_create(reader5,NULL,lock_read,reader5); pthread_create(reader6,NULL,lock_read,reader6); //主线程等待创建的子线程运行完成 pthread_join(writer1,NULL); pthread_join(writer2,NULL); pthread_join(reader1,NULL); pthread_join(reader2,NULL); pthread_join(reader3,NULL); pthread_join(reader4,NULL); pthread_join(reader5,NULL); pthread_join(reader6,NULL); //销毁读写锁 pthread_rwlock_destroy(rwlock); return 0; }makefilerwlock_test_writer_unlock:rwlock_test_writer_unlock.c -$(CC) -o $ $^ -lpthread -./$ -rm ./$结果2加上写锁#includestdio.h #includepthread.h #includeunistd.h static pthread_rwlock_t rwlock PTHREAD_RWLOCK_INITIALIZER; int shared_data0; void *lock_writer(void *arg) { //给多个线程写入添加写锁 //同一时间只能有一个线程获取写锁会造成两个线程顺序执行 pthread_rwlock_wrlock(rwlock); int temp shared_data 1; sleep(1); shared_data temp; printf(当前是%s,shared_data为%d\n,(char*)arg,shared_data); //写入之后释放写锁 pthread_rwlock_unlock(rwlock); } void *lock_read(void *arg) { //读写锁中的读是可以由多个线程统一读取的 //获取读锁 pthread_rwlock_rdlock(rwlock); printf(当前是%s,shared_data为%d\n,(char*)arg,shared_data); pthread_rwlock_unlock(rwlock); } int main(int argc, char const *argv[]) { //显示初始化读写锁 pthread_rwlock_init(rwlock,NULL); pthread_t writer1,writer2,reader1,reader2,reader3,reader4,reader5,reader6; //创建两个写线程 pthread_create(writer1,NULL,lock_writer,writer1); pthread_create(writer2,NULL,lock_writer,writer2); //休眠等待 sleep(3); //创建读线程 pthread_create(reader1,NULL,lock_read,reader1); pthread_create(reader2,NULL,lock_read,reader2); pthread_create(reader3,NULL,lock_read,reader3); pthread_create(reader4,NULL,lock_read,reader4); pthread_create(reader5,NULL,lock_read,reader5); pthread_create(reader6,NULL,lock_read,reader6); //主线程等待创建的子线程运行完成 pthread_join(writer1,NULL); pthread_join(writer2,NULL); pthread_join(reader1,NULL); pthread_join(reader2,NULL); pthread_join(reader3,NULL); pthread_join(reader4,NULL); pthread_join(reader5,NULL); pthread_join(reader6,NULL); //销毁读写锁 pthread_rwlock_destroy(rwlock); return 0; }makefilerwlock_test:rwlock_test.c -$(CC) -o $ $^ -lpthread -./$ -rm ./$3、写饥饿四、条件变量测试用例#includestdio.h #includestdlib.h #includepthread.h #define BUFFER_SIZE 5 int buffer[BUFFER_SIZE]; int count 0; //初始化互斥锁 static pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; //初始化条件变量 static pthread_cond_t condvarPTHREAD_COND_INITIALIZER; //期望功能是读或者写的一方 一直进行读写操作 直到缓冲读完或者写满 暂时释放锁 void *producer(void * arg) { int item 1; //使用共同的变量 使用互斥锁 首先获取锁 pthread_mutex_lock(mutex); while (1) { //使用共同的变量 使用互斥锁 首先获取锁 //pthread_mutex_lock(mutex); //如果缓冲区写满 使用条件变量暂停当前线程 if (count BUFFER_SIZE) { //暂停线程 pthread_cond_wait(condvar,mutex); } //缓冲区没有满 buffer[count]item; printf(白月光发送了一个幸运数字%d\n,buffer[count-1]); //唤醒消费者 pthread_cond_signal(condvar); //释放锁 //pthread_mutex_unlock(mutex); } //释放锁 pthread_mutex_unlock(mutex); } void *consumer(void * arg) { //使用共同的变量 使用互斥锁 首先获取锁 pthread_mutex_lock(mutex); while (1) { if (count 0) { //缓存中没有消息可读 暂停线程 pthread_cond_wait(condvar,mutex); } printf(我收到白月光的幸运数字为%d\n,buffer[--count]); //通知生产者可以继续写 pthread_cond_signal(condvar); } //释放锁 pthread_mutex_unlock(mutex); } int main(int argc, char const *argv[]) { //创建两个线程 一个向buf中写 一个从buf中读 pthread_t producer_thread,consumer_thread; //创建生产者线程 pthread_create(producer_thread,NULL,producer,NULL); //创建消费者线程 pthread_create(consumer_thread,NULL,consumer,NULL); //主线程需要挂起等待两个子线程完成 pthread_join(producer_thread,NULL); pthread_join(consumer_thread,NULL); return 0; }makefilecondition_var:condition_var.c -$(CC) -o $ $^ -lpthread -./$ -rm ./$五、信号量1、定义使用信号量解决线程同步问题#includestdio.h #includeunistd.h #includefcntl.h #includesys/mman.h #includesys/stat.h #includesys/types.h #includesys/wait.h #includesemaphore.h int main(int argc, char const *argv[]) { char *shm_value_name unnamed_sem_shm_value; //创建信号量 使用共享内存创建 char *shm_sem_nameunnamed_sem_shm_sem; //创建内存共享对象 int value_fd shm_open(shm_value_name,O_CREAT|O_RDWR,0666); int sem_fd shm_open(shm_sem_name,O_CREAT|O_RDWR,0666); //调整内存共享对象的大小 ftruncate(value_fd,sizeof(int)); ftruncate(sem_fd,sizeof(sem_t)); //将内存共享对象映射到共享内存区域 int *value mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,value_fd,0); //初始化共享变量的值 *value 0; //将共享内存的信号信号量共享到内存区域 sem_t *sem mmap(NULL,sizeof(sem_t),PROT_READ|PROT_WRITE,MAP_SHARED,sem_fd,0); //初始化信号量的值 sem_init(sem,1,1); int pid fork(); if (pid 0) { perror(fork); } if(pid 0) { //信号量等待 sem_wait(sem); int tmp *value 1; sleep(1); *value tmp; //信号量唤醒 sem_post(sem); } else { //信号量等待 sem_wait(sem); int tmp *value 1; sleep(1); *value tmp; //信号量唤醒 sem_post(sem); //等待子进程执行完毕 waitpid(pid,NULL,0); printf(this is father ,child finished\n); printf(the final value is %d\n,*value); } //父进程执行到这里子进程已经执行完毕 销毁信号量 if (pid 0) { if (sem_destroy(sem) -1) { perror(sem_destroy); } } //无论父子进程都应该解除信号量并关闭信号量的文件描述符 if (munmap(sem,sizeof(sem_t)) -1) { perror(munmap sem); } if (close(sem_fd) -1) { perror(close sem_fd); } //无论父子进程都应该解除共享内存的映射并关闭共享对象的文件描述符 if (munmap(value,sizeof(int)) -1) { perror(munmap value); } if (close(value_fd) -1) { perror(close value_fd); } //如果调用时别的进程仍在使用共享对象则等待所有进程释放资源后才会销毁相关资源 //shm_unlink只能调用一次这里在父进程中调用shm_unlink if (pid 0) { if (shm_unlink(shm_value_name) -1) { perror(father shm_unlink shm_value_name); } if (shm_unlink(shm_sem_name) -1) { perror(father shm_unlink shm_sem_name); } } return 0; }makefileunnamed_sem_bin_process:unnamed_sem_bin_process.c -$(CC) -o $ $^ -lrt -lpthread -./$ -rm ./$作为计数信号量用于线程间通信#includestdio.h #includeunistd.h #includesemaphore.h #includestdlib.h #includetime.h #includepthread.h sem_t *full; sem_t *empty; int shard_num; int rand_num() { srand(time(NULL)); return rand(); } void *producer(void *arg) { for (int i 0; i 5; i) { //获取信号量 //最开始empty 为1 可以减1 正常执行 //下次再到这里 empty为0 不能减1 不能执行 sem_wait(empty); printf(\n第%d轮数据传输\n,i1); sleep(1); shard_numrand_num(); //释放信号量 //使full加1 此时消费者就能够获取信号量 sem_post(full); } } void *consumer(void *arg) { for (int i 0; i 5; i) { //获取信号量 //最开始full为0 不能减1 卡住挂起 sem_wait(full); printf(\n第%d轮消费者读取数据\n,i1); sleep(1); printf(接收到的数据是%d,shard_num); //释放信号量 //消费者执行一轮 释放信号empty1 生产者就能获取信号量 sem_post(empty); } } int main(int argc, char const *argv[]) { fullmalloc(sizeof(sem_t)); emptymalloc(sizeof(sem_t)); //初始化信号量 sem_init(empty,0,1); sem_init(full,0,0); //创建生产者和消费者的线程 pthread_t producer_id,consumer_id; pthread_create(producer_id,NULL,producer,NULL); pthread_create(consumer_id,NULL,consumer,NULL); //等待线程全部执行完成 pthread_join(producer_id,NULL); pthread_join(consumer_id,NULL); //销毁信号量 sem_destroy(full); sem_destroy(empty); return 0; }makefileunnamed_sem_count_thread:unnamed_sem_count_thread.c -$(CC) -o $ $^ -lrt -lpthread -./$ -rm ./$作为计数信号量用于进程间通信#includestdio.h #includeunistd.h #includestdlib.h #includepthread.h #includefcntl.h #includesemaphore.h #includesys/mman.h #includesys/stat.h #includesys/types.h #includesys/wait.h int main(int argc, char const *argv[]) { char *shm_nameunnamed_sem_shm; //创建共享内存 int fdshm_open(shm_name,O_RDWR|O_CREAT,0666); //调整共享内存大小 ftruncate(fd,sizeof(sem_t)); //完成映射 sem_t *semmmap(NULL,sizeof(sem_t),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //初始化信号量 sem_init(sem,1,0); //创建父子进程 pid_t pid fork(); if (pid 0) { perror(fork); } if (pid 0) { //子进程 sleep(1); printf(这是子进程\n); sem_post(sem); } else { //父进程 //子进程睡眠1s保证父进程先执行 //sem_wait sem0 无法减1 卡住 sem_wait(sem); printf(这是父进程\n); waitpid(pid,NULL,0); } //回收资源 if (pid0) { if (sem_destroy(sem) -1) { perror(sem_destroy); } } //父子进程都需要关闭文件描述符 if (munmap(sem,sizeof(sem)) -1) { perror(munmap); } if (close(fd) -1) { perror(close); } if (pid 0) { if (shm_unlink(shm_name) -1) { perror(shm_unlink); } } return 0; }makefileunnamed_sem_count_process:unnamed_sem_count_process.c -$(CC) -o $ $^ -lrt -lpthread -./$ -rm ./$#includestdio.h #includeunistd.h #includefcntl.h #includesys/mman.h #includesys/stat.h #includesys/types.h #includesys/wait.h #includesemaphore.h int main(int argc, char const *argv[]) { char *shm_value_name /unnamed_sem_shm_value; char* sem_name/named_sem_shm; //创建内存共享对象 int value_fd shm_open(shm_value_name,O_CREAT|O_RDWR,0666); //初始化有名信号量 sem_t * sem sem_open(sem_name,O_CREAT,0666,1); //调整内存共享对象的大小 ftruncate(value_fd,sizeof(int)); //将内存共享对象映射到共享内存区域 int *value mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,value_fd,0); //初始化共享变量的值 *value 0; int pid fork(); if (pid 0) { perror(fork); } if(pid 0) { sem_wait(sem); int tmp *value 1; sleep(1); *value tmp; sem_post(sem); } else { sem_wait(sem); int tmp *value 1; sleep(1); *value tmp; sem_post(sem); //等待子进程执行完毕 waitpid(pid,NULL,0); printf(this is father ,child finished\n); printf(the final value is %d\n,*value); } //无论父子进程都应该解除共享内存的映射并关闭共享对象的文件描述符 if (munmap(value,sizeof(int)) -1) { perror(munmap value); } if (sem_close(sem) -1) { perror(close sem_close); } if (close(value_fd) -1) { perror(close value_fd); } //如果调用时别的进程仍在使用共享对象则等待所有进程释放资源后才会销毁相关资源 //shm_unlink只能调用一次这里在父进程中调用shm_unlink if (pid 0) { if (shm_unlink(shm_value_name) -1) { perror(father shm_unlink shm_value_name); } if (shm_unlink(sem_name)-1) { perror(shm_unlink); } } return 0; }makefilenamed_sem_bin:named_sem_bin.c -$(CC) -o $ $^ -lrt -lpthread -./$ -rm ./$