FEATURED · 精选文章

Linux应用开发(五)——线程

发布时间 / 2026/9/14 20:07:29
来源 / 创域科博编辑部
栏目 / 资讯中心
Linux应用开发(五)——线程 一、线程基础1、线程的理解每个用户进程有自己的地址空间系统为每个用户进程创建一个 task_struct来描述该进程该结构体中包含了一个指针指向该进程的虚拟地址空间映射表实际上task_struct 和地址空间映射表一起用来表示一个进程在32位系统当中每一个进程可以访问 0-4G 的地址空间如果这个地址在物理不存在则用mmu去虚拟一个地址。由于进程的地址空间是私有的因此在进程间切换时系统开销比较大。为了提高系统的性能许多操作系统规范里引入了轻量级进程的概念也被称为线程在同一个进程中创建的线程共享该进程的地址空间Linux里同样用task_struct来描述一个线程。线程和进程都参与统一的调度通常线程指的是共享相同地址空间的多个任务2、进程与线程的对比进程就相当于5个人占用5个房间线程就相当于5个人占用1个房间线程的优点 更加节省内存 大大提高了任务切换的效率 线程间可以使用全局变量进行通信。线程的缺点 安全性与稳定性不如进程有一个线程崩溃后 可能就会造成整个进程崩溃。进程的优点 安全性与稳定性比线程高1个进程崩溃不会对别的进程照成影响。进程的缺点 任务切换效率低进程间通信机制比较比较繁琐占用内存比线程高。3、线程库 NPTL多线程通过第三方的线程库来实现New POSIX Thread Library NPTL是早期Linux Threads的改进采用1:1的线程模型显著的提高了运行效率信号处理效率更高一个进程中的多个线程共享以下资源可执行的指令静态数据进程中打开的文件描述符信号处理函数当前工作目录用户ID用户组ID每个线程私有的资源如下线程ID (TID)PC(程序计数器)和相关寄存器堆栈局部变量返回地址错误号 (errno)信号掩码和优先级执行状态和属性NPTL线程库中提供了如下基本操作创建线程 pthread_create回收线程 pthread_join退出线程 pthread_exit取消线程 pthread_cancel线程间同步和互斥机制信号量、互斥锁、条件变量二、线程的API接口1、pthread_create 创建线程int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *),void* arg);函数功能创建一个新的线程函数参数【thread】创建线程的线程号 , 和进程号一致 。【attr】线程的属性 一般设置位NULL。【start_routine】void *(*start_routine) (void *) 从语法的角度上去看 start_routine是一个指针, 一个函数类型的指针, 一个形参为void * 返回值也是void * 类型的函数指针要创建线程调用的函数这个函数会在线程创建后自动被调用并运行。【arg】给线程函数传递的参数函数返回值成功返回0失败返回错误号#include stdio.h #include stdlib.h #include string.h #include unistd.h #include pthread.h // 线程函数 void *thread1_func(void *arg) { printf(线程1:arg %d\n, *((int *)arg)); // 线程1的参数 while (1) { printf(thread1_func is running\n); sleep(1); } return NULL; } // 线程函数2 void *thread2_func(void *arg) { printf(线程2:arg %d\n, *((int *)arg)); // 线程2的参数 while (1) { printf(thread2_func is running\n); sleep(1); } return NULL; } // 线程函数3 void *thread3_func(void *arg) { printf(线程3:arg %d\n, *((int *)arg)); // 线程3的参数 while (1) { printf(thread3_func is running\n); sleep(1); } return NULL; } int main(int argc, char const *argv[]) { pthread_t tid1; // 线程id1 pthread_t tid2; // 线程id2 pthread_t tid3; // 线程id3 int data1 100, data2 200, data3 300; int ret pthread_create(tid1, NULL, thread1_func, data1); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程1:tid1 %d\n, (int)tid1); // 线程1的id // 创建线程2 ret pthread_create(tid2, NULL, thread2_func, data2); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程2:tid2 %d\n, (int)tid2); // 线程2的id // 创建线程3 ret pthread_create(tid3, NULL, thread3_func, data3); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程3:tid3 %d\n, (int)tid3); // 线程3的id while (1) { printf(main thread is running\n); sleep(1); } return 0; }2、pthread_exit 退出线程void pthread_exit(void *retval);函数功能结束并返回线程的状态函数参数retval线程要返回的内容函数返回值无返回值3、pthread_join 回收线程int pthread_join(pthread_t thread, void **retval);函数功能回收一个线程函数参数thread要等待线程的tidretval线程的返回值函数返回值成功返回0失败返回错误号On success, pthread_join() returns 0; on error, it returns an error number.4、pthread_cancel 取消线程int pthread_cancel(pthread_t thread);函数功能取消一个线程函数参数thread要取消的线程号函数返回值成功返回0失败返回错误号On success, pthread_cancel() returns 0; on error, it returns a nonzero error number.5、实例获取线程返回状态#include stdio.h #include stdlib.h #include string.h #include unistd.h #include pthread.h // 线程函数 void *thread1_func(void *arg) { static int retval 0; // 线程1的返回值 printf(线程1:arg %d\n, *((int *)arg)); // 线程1的参数 printf(thread1_func is running\n); sleep(10); pthread_exit(retval); } // 线程函数2 void *thread2_func(void *arg) { static int retval -1; // 线程2的返回值 printf(线程2:arg %d\n, *((int *)arg)); // 线程2的参数 printf(thread2_func is running\n); sleep(10); pthread_exit(retval); } // 线程函数3 void *thread3_func(void *arg) { printf(线程3:arg %d\n, *((int *)arg)); // 线程3的参数 while (1) { printf(thread3_func is running\n); sleep(1); } return NULL; } int main(int argc, char const *argv[]) { pthread_t tid1; // 线程id1 pthread_t tid2; // 线程id2 pthread_t tid3; // 线程id3 int data1 100, data2 200, data3 300; int ret pthread_create(tid1, NULL, thread1_func, data1); if (ret ! 0) { perror(pthread_create); return -1; } // 创建线程2 ret pthread_create(tid2, NULL, thread2_func, data2); if (ret ! 0) { perror(pthread_create); return -1; } // 创建线程3 ret pthread_create(tid3, NULL, thread3_func, data3); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程1:tid1 %ld\n, tid1); // 线程1的id printf(线程2:tid2 %ld\n, tid2); // 线程2的id printf(线程3:tid3 %ld\n, tid3); // 线程3的id sleep(5); // 等待5秒 // 取消线程3 printf(取消线程3:tid3 %d\n, (int)tid3); // 线程3的id ret pthread_cancel(tid3); if (ret ! 0) { perror(pthread_cancel); return -1; } // 回收线程1 void *retval; ret pthread_join(tid1, retval); if (ret ! 0) { perror(pthread_join); return -1; } printf(线程1的返回值 %d\n, *((int *)retval)); // 线程1的返回值 // 回收线程2 ret pthread_join(tid2, retval); if (ret ! 0) { perror(pthread_join); return -1; } printf(线程2的返回值 %d\n, *((int *)retval)); // 线程2的返回值 while (1) { printf(main thread is running\n); sleep(1); } return 0; }8、实例线程的访问共享资源的bug#include stdio.h #include stdlib.h #include string.h #include unistd.h #include pthread.h #define NSize 64 char buf[NSize1]{0}; // 线程函数 void *thread1_func(void *arg) { printf(线程1:arg %d\n, *((int *)arg)); // 线程1的参数 while (1) { memset(buf, O, 32); usleep(1000); // 1ms memset(buf32, O, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms } return NULL; } // 线程函数2 void *thread2_func(void *arg) { printf(线程2:arg %d\n, *((int *)arg)); // 线程2的参数 while (1) { memset(buf, -, 32); usleep(1000); // 1ms memset(buf32, -, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms } return NULL; } // 线程函数3 void *thread3_func(void *arg) { printf(线程3:arg %d\n, *((int *)arg)); // 线程3的参数 while (1) { printf(buf %s\n, buf); // 线程3的参数 sleep(1); } return NULL; } int main(int argc, char const *argv[]) { pthread_t tid1; // 线程id1 pthread_t tid2; // 线程id2 pthread_t tid3; // 线程id3 int data1 100, data2 200, data3 300; int ret pthread_create(tid1, NULL, thread1_func, data1); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程1:tid1 %d\n, (int)tid1); // 线程1的id // 创建线程2 ret pthread_create(tid2, NULL, thread2_func, data2); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程2:tid2 %d\n, (int)tid2); // 线程2的id // 创建线程3 ret pthread_create(tid3, NULL, thread3_func, data3); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程3:tid3 %d\n, (int)tid3); // 线程3的id while (1) { printf(buf %s\n, buf); // 线程3的参数 sleep(1); } return 0; }三、线程间同步与互斥机制之信号量1、线程的优缺点多线程共享同一个进程的地址空间优点线程间很容易进行通信 通过全局变量实现数据共享和交换缺点多个线程同时访问共享对象时需要引入同步和互斥机制2、信号量同步(synchronization)指的是多个任务(线程) 按照约定的顺序相互配合完成一件事情1968年Edsgar Dijkstra基于信号量的概念 提出了一种同步机制。由信号量来决定线程是继续运行还是阻塞等待 。3、线程间 /操作信号量代表某一类资源其值表示系统中该资源的数量信号量是一个受保护的变量只能通过三种操作来访问初始化、操作(申请资源)、操作(释放资源)信号量的值为非负整数() 含义如下:if (信号量的值大于0) { 申请资源的线程继续运行 信号量的值减一 } else { 申请资源的任务阻塞 }V() 含义如下:if (没有任务在等待该资源) { 信号量的值加一 } else { 唤醒第一个等待的任务让其继续运行 }posix中定义了两类信号量无名信号量(基于内存的信号量) 主要用于线程间使用 进程间很少使用有名信号量(基于文件的信号量) , 主要用于进程间使用线程间很少使用4、sem_init 初始化一个无名信号量#include semaphore.h int sem_init(sem_t *sem, int pshared, unsigned int value);函数功能初始化一个无名的信号量函数参数【sem】要初始化的信号量【pshared】0在线程间使用非0在进程间使用【value】 信号量的值函数返回值成功返回0失败返回-1 并设置errnosem_init() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.5、sem_getvalue 获取无名信号量的值#include semaphore.h int sem_getvalue(sem_t *sem, int *sval);函数功能获取一个无名信号量的值函数参数【sem】要获取的信号量【sval】获取的信号量值函数返回值成功返回0失败返回-1 并设置errnosem_getvalue() returns 0 on success; on error, -1 is returned and errno is set to indicate the error.6、sem_wait 申请一个无名信号量(P操作)#include semaphore.h int sem_wait(sem_t *sem);函数功能申请一个无名信号量这个是P操作函数参数【sem】要获取信号量函数返回值成功返回0失败返回-1 并设置errnoAll of these functions return 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno is set to indicate the error.7、sem_post 释放一个无名信号量(V操作)#include semaphore.h int sem_post(sem_t *sem);函数功能释放一个无名信号量这个是V操作函数参数【sem】要释放的信号量函数返回值成功返回0失败返回-1 并设置errnosem_post() returns 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno is set to indicate the error.8、sem_destroy 销毁一个无名信号量#include semaphore.h int sem_destroy(sem_t *sem);函数功能销毁一个无名信号量函数参数【sem】要销毁信号量函数返回值成功返回0失败返回-1 并设置errnosem_destroy() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.使用信号量来实现互斥9、实例使用信号量来实现互斥#include stdio.h #include stdlib.h #include string.h #include unistd.h #include pthread.h #include semaphore.h #define NSize 64 char buf[NSize1]{0}; sem_t sem; // 信号量 // 线程函数 void *thread1_func(void *arg) { printf(线程1:arg %d\n, *((int *)arg)); // 线程1的参数 while (1) { sem_wait(sem); // 等待信号量 P操作 阻塞等待信号量为0 memset(buf, O, 32); usleep(1000); // 1ms memset(buf32, O, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms sem_post(sem); // 发送信号量 V操作 信号量加1 } return NULL; } // 线程函数2 void *thread2_func(void *arg) { printf(线程2:arg %d\n, *((int *)arg)); // 线程2的参数 while (1) { sem_wait(sem); // 等待信号量 P操作 阻塞等待信号量为0 memset(buf, -, 32); usleep(1000); // 1ms memset(buf32, -, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms sem_post(sem); // 发送信号量 V操作 信号量加1 } return NULL; } // 线程函数3 void *thread3_func(void *arg) { printf(线程3:arg %d\n, *((int *)arg)); // 线程3的参数 while (1) { sem_wait(sem); // 等待信号量 P操作 阻塞等待信号量为0 printf(buf %s\n, buf); // 线程3的参数 sem_post(sem); // 发送信号量 V操作 信号量加1 sleep(1); } return NULL; } int main(int argc, char const *argv[]) { pthread_t tid1; // 线程id1 pthread_t tid2; // 线程id2 pthread_t tid3; // 线程id3 int data1 100, data2 200, data3 300; // 初始化信号量 sem_init(sem, 0, 1); // 0表示线程间共享初始值为0 int ret pthread_create(tid1, NULL, thread1_func, data1); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程1:tid1 %d\n, (int)tid1); // 线程1的id // 创建线程2 ret pthread_create(tid2, NULL, thread2_func, data2); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程2:tid2 %d\n, (int)tid2); // 线程2的id // 创建线程3 ret pthread_create(tid3, NULL, thread3_func, data3); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程3:tid3 %d\n, (int)tid3); // 线程3的id while (1) { sem_wait(sem); // 等待信号量 P操作 阻塞等待信号量为0 printf(buf %s\n, buf); // 线程3的参数 sem_post(sem); // 发送信号量 V操作 信号量加1 sleep(1); } return 0; }10、实例使用信号量来实现同步#include stdio.h #include stdlib.h #include string.h #include unistd.h #include pthread.h #include semaphore.h #define NSize 64 char buf[NSize1]{0}; sem_t sem_w1; // 信号量 写锁 sem_t sem_w2; // 信号量 写锁 sem_t sem_r1; // 信号量 读锁 sem_t sem_r2; // 信号量 读锁 // 线程函数 void *thread1_func(void *arg) { printf(线程1:arg %d\n, *((int *)arg)); // 线程1的参数 while (1) { sem_wait(sem_w1); // 等待信号量 P操作 阻塞等待信号量为0 memset(buf, O, 32); usleep(1000); // 1ms memset(buf32, O, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms sem_post(sem_r1); // 发送信号量 V操作 信号量加1 } return NULL; } // 线程函数2 void *thread2_func(void *arg) { printf(线程2:arg %d\n, *((int *)arg)); // 线程2的参数 while (1) { sem_wait(sem_w2); // 等待信号量 P操作 阻塞等待信号量为0 memset(buf, -, 32); usleep(1000); // 1ms memset(buf32, -, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms sem_post(sem_r2); // 发送信号量 V操作 信号量加1 } return NULL; } // 线程函数3 void *thread3_func(void *arg) { printf(线程3:arg %d\n, *((int *)arg)); // 线程3的参数 while (1) { sem_wait(sem_r1); // 等待信号量 P操作 阻塞等待信号量为0 printf(buf %s\n, buf); // 线程3的参数 sem_post(sem_w2); // 发送信号量 V操作 信号量加1 sleep(1); } return NULL; } int main(int argc, char const *argv[]) { pthread_t tid1; // 线程id1 pthread_t tid2; // 线程id2 pthread_t tid3; // 线程id3 int data1 100, data2 200, data3 300; // 初始化信号量 sem_init(sem_w1, 0, 1); // 0表示线程间共享初始值为1 sem_init(sem_w2, 0, 0); // 0表示线程间共享初始值为0 sem_init(sem_r1, 0, 0); // 0表示线程间共享初始值为0 sem_init(sem_r2, 0, 0); // 0表示线程间共享初始值为0 int ret pthread_create(tid1, NULL, thread1_func, data1); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程1:tid1 %d\n, (int)tid1); // 线程1的id // 创建线程2 ret pthread_create(tid2, NULL, thread2_func, data2); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程2:tid2 %d\n, (int)tid2); // 线程2的id // 创建线程3 ret pthread_create(tid3, NULL, thread3_func, data3); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程3:tid3 %d\n, (int)tid3); // 线程3的id while (1) { sem_wait(sem_r2); // 等待信号量 P操作 阻塞等待信号量为0 printf(buf %s\n, buf); // 线程3的参数 sem_post(sem_w1); // 发送信号量 V操作 信号量加1 sleep(1); } return 0; }四、线程间同步与互斥机制之互斥锁1、互斥锁的理解引入互斥(mutual exclusion)锁的目的是用来保证共享数据操作的完整性。互斥锁主要用来保护临界资源每个临界资源都由一个互斥锁来保护任何时刻最多只能有一个线程能访问该资源线程必须先获得互斥锁才能访问临界资源访问完资源后释放该锁。如果无法获得锁线程会阻塞直到获得锁为止2、安装互斥锁库互斥锁不是ubuntu中的标准库是一个第三方的库, 需要安装对应的库sudo apt install manpages-posix manpages-posix-dev3、pthread_mutex_init初始化一个互斥锁#include pthread.h int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER;函数功能初始化一个互斥锁函数参数【mutex】要初始化的锁【attr】锁的属性 默认为NULL函数返回值成功返回0失败返回错误号If successful, the pthread_mutex_destroy() and pthread_mutex_init() functions shall return zero; otherwise, an error number shall be returned to indicate the error.4、pthread_mutex_destroy销毁一个互斥锁#include pthread.h int pthread_mutex_destroy(pthread_mutex_t *mutex); pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER;函数功能销毁一个互斥锁函数参数【mutex】要销毁的锁函数返回值成功返回0失败返回错误号If successful, the pthread_mutex_destroy() and pthread_mutex_init() functions shall return zero; otherwise, an error number shall be returned to indicate the error.5、pthread_mutex_lock申请一个互斥锁(P操作)#include pthread.h int pthread_mutex_lock(pthread_mutex_t *mutex);函数功能申请一个互斥锁函数参数【mutex】要申请的锁函数返回值成功返回0失败返回错误号If successful, the pthread_mutex_lock(), pthread_mutex_trylock(), and pthread_mutex_unlock() func‐tions shall return zero; otherwise, an error number shall be returned to indicate the error.6、pthread_mutex_unlock释放一个互斥锁(V操作)#include pthread.h int pthread_mutex_unlock(pthread_mutex_t *mutex);函数功能释放一个互斥锁函数参数【mutex】要释放的锁函数返回值成功返回0失败返回错误号If successful, the pthread_mutex_lock(), pthread_mutex_trylock(), and pthread_mutex_unlock() func‐tions shall return zero; otherwise, an error number shall be returned to indicate the error.7、实例使用互斥锁实现互斥#include stdio.h #include stdlib.h #include string.h #include unistd.h #include pthread.h #define NSize 64 char buf[NSize1]{0}; pthread_mutex_t mutex ; // 互斥锁 // 线程函数 void *thread1_func(void *arg) { printf(线程1:arg %d\n, *((int *)arg)); // 线程1的参数 while (1) { pthread_mutex_lock(mutex); // 加锁 memset(buf, O, 32); usleep(1000); // 1ms memset(buf32, O, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms pthread_mutex_unlock(mutex); // 解锁 } return NULL; } // 线程函数2 void *thread2_func(void *arg) { printf(线程2:arg %d\n, *((int *)arg)); // 线程2的参数 while (1) { pthread_mutex_lock(mutex); // 加锁 memset(buf, -, 32); usleep(1000); // 1ms memset(buf32, -, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms pthread_mutex_unlock(mutex); // 解锁 } return NULL; } // 线程函数3 void *thread3_func(void *arg) { printf(线程3:arg %d\n, *((int *)arg)); // 线程3的参数 while (1) { pthread_mutex_lock(mutex); // 加锁 printf(buf %s\n, buf); // 线程3的参数 pthread_mutex_unlock(mutex); // 解锁 sleep(1); } return NULL; } int main(int argc, char const *argv[]) { pthread_t tid1; // 线程id1 pthread_t tid2; // 线程id2 pthread_t tid3; // 线程id3 int data1 100, data2 200, data3 300; // 初始化互斥锁 // 锁被初始化后 锁的状态是开的 可以被任意线程加锁 // pthread_mutex_lock(mutex); // 加锁 // pthread_mutex_unlock(mutex); // 解锁 int ret pthread_mutex_init(mutex, NULL); if (ret ! 0) { perror(pthread_mutex_init); return -1; } ret pthread_create(tid1, NULL, thread1_func, data1); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程1:tid1 %d\n, (int)tid1); // 线程1的id // 创建线程2 ret pthread_create(tid2, NULL, thread2_func, data2); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程2:tid2 %d\n, (int)tid2); // 线程2的id // 创建线程3 ret pthread_create(tid3, NULL, thread3_func, data3); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程3:tid3 %d\n, (int)tid3); // 线程3的id while (1) { pthread_mutex_lock(mutex); // 加锁 printf(buf %s\n, buf); // 线程3的参数 pthread_mutex_unlock(mutex); // 解锁 sleep(1); } return 0; }8、实例使用互斥锁实现同步#include stdio.h #include stdlib.h #include string.h #include unistd.h #include pthread.h #define NSize 64 char buf[NSize 1] {0}; pthread_mutex_t mutex_w1; // 互斥锁 pthread_mutex_t mutex_w2; // 互斥锁 pthread_mutex_t mutex_r1; // 互斥锁 pthread_mutex_t mutex_r2; // 互斥锁 // 线程函数 void *thread1_func(void *arg) { printf(线程1:arg %d\n, *((int *)arg)); // 线程1的参数 while (1) { pthread_mutex_lock(mutex_w1); // 加锁 memset(buf, O, 32); usleep(1000); // 1ms memset(buf 32, O, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms pthread_mutex_unlock(mutex_r1); // 解锁 } return NULL; } // 线程函数2 void *thread2_func(void *arg) { printf(线程2:arg %d\n, *((int *)arg)); // 线程2的参数 while (1) { pthread_mutex_lock(mutex_w2); // 加锁 memset(buf, -, 32); usleep(1000); // 1ms memset(buf 32, -, 32); // 保证最后1个元素为 \0 usleep(1000); // 1ms pthread_mutex_unlock(mutex_r2); // 解锁 } return NULL; } // 线程函数3 void *thread3_func(void *arg) { printf(线程3:arg %d\n, *((int *)arg)); // 线程3的参数 while (1) { pthread_mutex_lock(mutex_r1); // 加锁 printf(buf %s\n, buf); // 线程3的参数 pthread_mutex_unlock(mutex_w2); // 解锁 sleep(1); } return NULL; } int main(int argc, char const *argv[]) { pthread_t tid1; // 线程id1 pthread_t tid2; // 线程id2 pthread_t tid3; // 线程id3 int data1 100, data2 200, data3 300; int ret; // 初始化互斥锁 // 锁被初始化后 锁的状态是开的 可以被任意线程加锁 // pthread_mutex_lock(mutex); // 加锁 // pthread_mutex_unlock(mutex); // 解锁 ret pthread_mutex_init(mutex_w1, NULL); if (ret ! 0) { perror(pthread_mutex_init); return -1; } ret pthread_mutex_init(mutex_w2, NULL); if (ret ! 0) { perror(pthread_mutex_init); return -1; } ret pthread_mutex_init(mutex_r1, NULL); if (ret ! 0) { perror(pthread_mutex_init); return -1; } ret pthread_mutex_init(mutex_r2, NULL); if (ret ! 0) { perror(pthread_mutex_init); return -1; } // 上锁 mutex_w2 ret pthread_mutex_lock(mutex_w2); if (ret ! 0) { perror(pthread_mutex_lock); return -1; } // 上锁 mutex_r1 ret pthread_mutex_lock(mutex_r1); if (ret ! 0) { perror(pthread_mutex_lock); return -1; } // 上锁 mutex_r2 ret pthread_mutex_lock(mutex_r2); if (ret ! 0) { perror(pthread_mutex_lock); return -1; } ret pthread_create(tid1, NULL, thread1_func, data1); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程1:tid1 %ld\n, tid1); // 线程1的id // 创建线程2 ret pthread_create(tid2, NULL, thread2_func, data2); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程2:tid2 %ld\n, tid2); // 线程2的id // 创建线程3 ret pthread_create(tid3, NULL, thread3_func, data3); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程3:tid3 %ld\n, tid3); // 线程3的id while (1) { pthread_mutex_lock(mutex_r2); // 加锁 printf(buf %s\n, buf); // 线程3的参数 pthread_mutex_unlock(mutex_w1); // 解锁 sleep(1); } return 0; }五、线程间同步与互斥机制之条件变量1、条件变量的理解条件变量是利用线程间共享的全局变量进行同步的一种机制。主要包括两个动作一个线程等待条件变量的条件成立而挂起另一个线程使条件成立给出条件成立信号。为了防止竞争条件变量的使用总是和一个互斥锁结合在一起。2、pthread_cond_init初始化一个条件变量#include pthread.h int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);函数功能要初始化的一个条件变量这个条件变量的初始是不成立的状态函数参数cond要初始化的条件变量的地址attr条件变量的属性 默认为NULL函数返回值成功返回0失败返回错误号If successful, the pthread_cond_destroy() and pthread_cond_init() functions shall return zero; otherwise, an error number shall be returned to indicate the error.3、pthread_cond_wait等待一个条件变量成立#include pthread.h int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);函数功能要等待的一个条件变量函数参数cond要等待的条件变量mutex保护条件变量要用到的锁函数返回值成功返回0失败返回错误号Upon successful completion, a value of zero shall be returned; otherwise, an error number shall be returned to indicate the error.4、pthread_cond_signal激活条件变量#include pthread.h int pthread_cond_signal(pthread_cond_t *cond);函数功能只是激活一个线程的条件变量成立要激活的条件变量函数参数cond要释放的条件变量函数返回值成功返回0失败返回错误号Upon successful completion, a value of zero shall be returned; otherwise, an error number shall be returned to indicate the error.5、pthread_cond_broadcast激活所有的条件变量#include pthread.h int pthread_cond_broadcast(pthread_cond_t *cond);函数功能激活该条件变量上的所有等待线程释放等待在这个条件变量上所有的线程让所有等待的线程立即条件成立立即可以获得函数参数cond要激活的条件变量函数返回值成功返回0失败返回错误号Upon successful completion, a value of zero shall be returned; otherwise, an error number shall be returned to indicate the error.6、条件变量使用深入理解在操作系统中不允许带着锁去进入等待态(阻塞睡眠)。pthread_mutex_lock(mutex); // 条件变量需要用一个互斥锁去保护 /* 第1种情况: 条件变量(cond)成立, pthread_cond_wait 函数立即返回 */ /* 第2种情况: 条件变量(cond)不成立, pthread_cond_wait 函数等待, 在进入阻塞前释放mutex, 之后进入阻塞(睡眠, 等待), 函数不返回, 线程进入等待态, 锁的状态被恢复. 过了一段时间后, 在别的线程中使用了pthread_cond_signal 或者 pthread_cond_broadcast 去激活了该条件变量线程被唤醒, 首先上锁条件变量, 条件变量成立, 函数返回 */ pthread_cond_wait(cond, mutex); pthread_mutex_unlock(mutex); // 条件变量操作完成后, 释放这个锁7、条件变量的使用#include stdio.h #include stdlib.h #include string.h #include unistd.h #include pthread.h #define NSize 64 char buf[NSize 1] {0}; pthread_mutex_t mutex; // 互斥锁 pthread_cond_t cond1, cond2, cond3; // 条件变量 // 线程函数 void *thread1_func(void *arg) { printf(线程1:arg %d\n, *((int *)arg)); // 线程1的参数 while (1) { // pthread_handler1 is running pthread_mutex_lock(mutex); // 加锁 pthread_cond_wait(cond1, mutex); // 等待条件变量cond1 printf(pthread_handler1 is running\n); pthread_mutex_unlock(mutex); // 解锁 } return NULL; } // 线程函数2 void *thread2_func(void *arg) { printf(线程2:arg %d\n, *((int *)arg)); // 线程2的参数 while (1) { // pthread_handler2 is running pthread_mutex_lock(mutex); // 加锁 pthread_cond_wait(cond2, mutex); // 等待条件变量cond2 printf(pthread_handler2 is running\n); pthread_mutex_unlock(mutex); // 解锁 } return NULL; } // 线程函数3 void *thread3_func(void *arg) { printf(线程3:arg %d\n, *((int *)arg)); // 线程3的参数 while (1) { // pthread_handler3 is running pthread_mutex_lock(mutex); // 加锁 pthread_cond_wait(cond3, mutex); // 等待条件变量cond3 printf(pthread_handler3 is running\n); pthread_mutex_unlock(mutex); // 解锁 } return NULL; } int main(int argc, char const *argv[]) { pthread_t tid1; // 线程id1 pthread_t tid2; // 线程id2 pthread_t tid3; // 线程id3 int data1 100, data2 200, data3 300; int ret; // 初始化互斥锁 // 锁被初始化后 锁的状态是开的 可以被任意线程加锁 // pthread_mutex_lock(mutex); // 加锁 // pthread_mutex_unlock(mutex); // 解锁 ret pthread_mutex_init(mutex, NULL); if (ret ! 0) { perror(pthread_mutex_init); return -1; } // 初始化条件变量 ret pthread_cond_init(cond1, NULL); if (ret ! 0) { perror(pthread_cond_init); return -1; } ret pthread_cond_init(cond2, NULL); if (ret ! 0) { perror(pthread_cond_init); return -1; } ret pthread_cond_init(cond3, NULL); if (ret ! 0) { perror(pthread_cond_init); return -1; } ret pthread_create(tid1, NULL, thread1_func, data1); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程1:tid1 %ld\n, tid1); // 线程1的id // 创建线程2 ret pthread_create(tid2, NULL, thread2_func, data2); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程2:tid2 %ld\n, tid2); // 线程2的id // 创建线程3 ret pthread_create(tid3, NULL, thread3_func, data3); if (ret ! 0) { perror(pthread_create); return -1; } printf(线程3:tid3 %ld\n, tid3); // 线程3的id usleep(1000 * 10); // 10ms while (1) { // 1:wakeup handler1 2:wakeup handler2 3:wakeup handler3 4: wakeup all handlers printf(请输入要唤醒的线程(1-4):); int choice; scanf(%d, choice); switch (choice) { case 1: pthread_cond_signal(cond1); break; case 2: pthread_cond_signal(cond2); break; case 3: pthread_cond_signal(cond3); break; case 4: pthread_cond_broadcast(cond1); pthread_cond_broadcast(cond2); pthread_cond_broadcast(cond3); break; default: printf(输入错误请重新输入\n); break; } usleep(1000 * 100); // 100ms } return 0; }
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻