多任务并发之线程

发布时间:2026/7/10 22:46:23

多任务并发之线程 线程什么是线程线程是一个轻量级的进程用来实现多任务并发。线程是操作系统任务调度的最小单位。线程由某个进程创建线程的创建线程由所在进程创建创建时进程为其分配独立的栈区空间默认8M。同一个进程中的线程共用所在进程的堆区、数据区、文本区线程的调度宏观并行从宏观角度多个任务同时执行微观串行微观角度多个任务按照一定顺序先后执行线程的消亡线程退出回收线程的资源空间进程和线程的区别线程相关接口pthread_create函数int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 功能创建并启动一个线程 参数 thread 保存线程ID的变量地址 attr 设置线程属性 NULL 按照默认属性创建 start_routine 函数指针线程启动后要执行的任务的函数地址线程任务函数 arg 传递给线程任务函数的参数 返回值 成功0 失败非0 注意1. 编译和链接时要加-lpthread 表示链接线程库。 2. 线程执行时线程所在的进程不能先退出pthread_exit()函数void pthread_exit(void *retval); 功能结束一个线程 参数 retval 可以用来保存线程退出时传递的参数 和return返回的指针类似 注意 线程退出 1. 在线程任务中return 2. 在线程任务中pthread_exit 3. 在线程中exit让所在进程直接退出phtread_self()函数功能获取当前线程的tid号pthread_join()函数int pthread_join(pthread_t thread, void **retval); 功能等待回收具有非分离属性的线程 参数 thread要回收的线程ID retval接收回收的线程退出时传递的参数通过pthread_exit参数return返回值传递 NULL 不接收参数 返回值 成功0 失败非0示例#include pthread.h #include stdio.h #include stdlib.h #include unistd.h void *th_task1(void *arg) { int cnt 0; int num *((int *)arg); while (1) { if (5 cnt) { // exit(0);//直接退出整个进程 pthread_exit(NULL); // return NULL; } printf(thread1 tid is %lx,num is %d\n, pthread_self(), num); sleep(1); } return NULL; } void *th_task2(void *arg) { while (1) { printf(thread2 tid is %lx\n, pthread_self()); sleep(1); } } int main(int argc, char **argv) { pthread_t tid[2]; int num 100; int ret pthread_create(tid[0], NULL, th_task1, num); if (ret ! 0) { fprintf(stderr, pthread_create error\n); return -1; } ret pthread_create(tid[1], NULL, th_task2, NULL); if (ret ! 0) { fprintf(stderr, pthread_create error\n); return -1; } pthread_join(tid[0], NULL); pthread_join(tid[1], NULL); return 0; }线程的分离属性分离属性 不需要被其他线程回收的线程称为具有分离属性的线程结束时可以被操作系统回收。非分离属性可以被其他线程回收或者结束的线程称为非分离属性的线程默认属性非分离属性设置线程分离属性int pthread_detach(pthread_t thread); 功能设置线程的分离属性 参数 thread要设置的线程的线程ID 返回值 成功0 失败0include stdio.h #include pthread.h void *task(void *arg) { } int main(int argc, const char *argv[]) { pthread_t tid; int cnt 0; while (1) { int ret pthread_create(tid, NULL, task, NULL); if (ret ! 0) { fprintf(stderr, pthread_create error\n); return -1; } pthread_detach(tid); cnt; printf(cnt %d\n, cnt); } return 0; }线程的互斥机制多线程访问临界资源时存在资源竞争问题。临界资源多个线程可以同时操作的资源比如全局变量共享内存等。如何解决资源竞争问题线程的互斥机制让多个线程在访问临界资源时具有排他性访问的特性互斥锁实现互斥机制创建互斥锁pthread_mutex_t初始化锁pthread_mutex_init加锁pthread_mutex_lock/pthread_mutex_trylock解锁pthread_mutex_unlock销毁锁pthread_mutex_destroyint pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); 功能初始化互斥锁 参数 mutex 互斥锁对象地址 attr 锁的属性 返回值 成功0 失败非0int pthread_mutex_lock(pthread_mutex_t *mutex); 功能以阻塞方式等待加锁 int pthread_mutex_trylock(pthread_mutex_t *mutex); 功能以非阻塞方式加锁如果该锁已被使用则返回 int pthread_mutex_unlock(pthread_mutex_t *mutex); 功能解锁/释放锁 int pthread_mutex_destroy(pthread_mutex_t *mutex); 功能销毁锁#include stdio.h #include pthread.h int num_g0; pthread_mutex_t mutex; void *task1(void *arg) { for(int i0;i5;i) { pthread_mutex_lock(mutex); num_gnum_g1; printf(num_g%d\n,num_g); pthread_mutex_unlock(mutex); } return NULL; } void *task2(void *arg) { for(int i0;i5;i) { pthread_mutex_lock(mutex); num_gnum_g1; printf(num_g%d\n,num_g); pthread_mutex_unlock(mutex); } return NULL; } int main(int argc, char **argv) { pthread_t tid[2]; pthread_mutex_init(mutex,NULL); pthread_create(tid[0],NULL,task1,NULL); pthread_create(tid[1],NULL,task2,NULL); pthread_join(tid[0],NULL); pthread_join(tid[1],NULL); pthread_mutex_destroy(mutex); return 0; }线程间同步机制线程间同步让多个线程任务执行某部分任务的时候具有先后顺序。同步方式信号量可以将信号量看成一个资源数当该资源数0的时候可以申请到信号量当资源时为0时申请信号量阻塞等待。申请完信号量时该信号量对应的资源数自动-1。释放对应的信号量时该信号量对应的资源数自动1。创建信号量sem_t sem;初始化信号量int sem_init(sem_t *sem, int pshared, unsigned int value); 功能初始化信号量 参数 sem初始化的信号量对象地址 pshared进程间共享还是线程间 0 线程间 非0进程间 value初始化的资源数 返回值 成功0 失败-1申请信号量P操作int sem_wait(sem_t *sem); int sem_trywait(sem_t *sem);释放信号量V操作int sem_post(sem_t *sem);销毁信号量int sem_destroy(sem_t *sem);示例#include pthread.h #include semaphore.h #include stdio.h char buff[1024] {0}; sem_t sem_w; sem_t sem_r; void *task1(void *arg) { while (1) { sem_wait(sem_w); //-1 fgets(buff, sizeof(buff), stdin); sem_post(sem_r); //1 } } void *task2(void *arg) { while (1) { sem_wait(sem_r); //-1 printf(buff %s\n, buff); sem_post(sem_w); //1 } } int main(int argc, const char *argv[]) { pthread_t tid[2]; sem_init(sem_w, 0, 1); sem_init(sem_r, 0, 0); pthread_create(tid[0], NULL, task1, NULL); pthread_create(tid[1], NULL, task2, NULL); pthread_join(tid[0], NULL); pthread_join(tid[1], NULL); sem_destroy(sem_w); sem_destroy(sem_r); return 0; }死锁死锁死锁指的是在多线程环境中每个执行流线程都有未释放的资源且互相请求对方未释放资 源从而导致陷入永久等待状态的情况。 现象 现象1忘记释放锁 现象2重复加锁 现象3多线程多锁抢占锁资源不当 如线程A获取了1锁线程B获取了2锁同时线程A还想获取2锁线程B还想获取1锁 *产生死锁的四个必要条件四条全中 死锁破掉任意一条 解除 1 互斥条件一个资源同一时刻只能被一个任务占用一个执行流获取锁后其它执行流不能再获取 该锁。 2 请求与保持条件已经拿着一部分资源不释放同时又去申请新的资源执行流本身使用着一把锁 并不释放还在请求别的锁。 3 不剥夺条件:资源只能由持有者主动释放系统/其他任务不能强行抢过来A执行流拿着锁其它 执行流不能释放。 4 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系多个执行流拿着对方想要的 锁并且各执行流还去请求对方的锁。 解决方法 1.锁一定要成对出现 2.使线程的加解锁顺序一致 3.破坏环路等待条件 使用非阻塞锁一旦线程发现请求的锁被使用就去释放自己拥有的资源

相关新闻