Linux--线程下

tech2025-11-12  6

信号量 – 线程级

信号量类似于一个特殊的计数器,当信号量值大于零,表示可以访问的临界资源的个数,等于零,对信号量执行P操作会阻塞 对信号量的P,V操作不一定非得在同一线程中 信号量方法: #include <semaphore.h> 信号量类型:sem_t 全局定义一个sem_t类型的信号量 初始化:int sem_init(sem_t *sem, int shared, int init_val); shared:设置信号量是否在进程间共享,Linux不支持,一般给零 init_val:信号量的初始值 P操作:int sem_wait(sem_t *sem); V操作:int sem_post(sem_t *sem); 销毁:int sem_destroy(sem_t *sem);

示例:主线程 函数线程 主线程获取用户输入,函数线程将用户输入的数据存储到a.txt中。 1.主线程获取的用户数据如何传递给函数线程:全局 堆区 栈区(空间指针需要传入才可共享) 2.函数线程只能在主线程获取到数据(直接存储在共享空间中),才能执行write操作 3.主线程只能在函数线程将数据写入文件后才能获取下一次数据

代码实现:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <assert.h> #include <math.h> #include <fcntl.h> #include <signal.h> #include <semaphore.h> #include <pthread.h> #define BUFFSIZE 128 sem_t sem1,sem2; void *fun(void *arg) { char *buff = (char *)arg; int fw = open("a.txt",O_WRONLY | O_CREAT | O_TRUNC,0664); assert(fw != -1); while(1) { sem_wait(&sem1); if(strncmp(buff,"end",3) == 0) break; write(fw,buff,strlen(buff)); memset(buff,0,BUFFSIZE); sem_post(&sem2); } } int main() { sem_init(&sem1,0,0); sem_init(&sem2,0,2); char buff[BUFFSIZE] = {0}; pthread_t id; int res = pthread_create(&id,NULL,fun,(void *)buff); assert(res == 0); while(1) { sem_wait(&sem2); printf("please input: "); fgets(buff,BUFFSIZE,stdin); sem_post(&sem1); if(strncmp(buff,"end",3) == 0) break; } pthread_join(id,NULL); sem_destroy(&sem1); sem_destroy(&sem2); exit(0); }

执行结果:

条件变量

为多个线程提供一个汇合的场所 wait再加锁状态下,将线程添加到条件变量对应的等待队列中,然后执行解锁操作 – 》将线程添加到队列与唤醒是互斥的 (用互斥锁保护,假如同时有两个线程,一个进行添加,一个进行唤醒,如果没有互斥锁保护,就不知道到底是添加还是唤醒,加上互斥锁,就是在添加的时候不能唤醒,唤醒的时候不能添加,更安全)

读写锁

读写锁有三种状态:读模式下加锁,写模式下加锁,不加锁,一次只能有一个线程占有写模式读写锁,但是多个线程可以同时占有读模式读写锁 如果当前是读加锁,另外一个线程试图写加锁请求,那么之后的读加锁都会阻塞,这样可以避免读模式长期被占用,写加锁请求却不能得到满足


线程安全

线程是并发运行的,而且线程之间共享进程的地址空间,所以在执行时,可能会修改共享数据,修改的时机也无法确定,所以最后的结果有不确定性 1.使用线程同步 2.不使用共享数据 – 》共享数据转化为非共享数据

不能保证线程安全的库函数: (方法种使用了全局或者数据可以共享的变量,所以不安全)

1.多线程种某个线程调用fork(),子进程会有和父进程相同数量的进程嘛? 多线程种一个线程调用fork创建子进程,子进程种只有fork这个线程会被启动运行,其他线程不会运行。


2.父进程被加锁的互斥锁fork后在子进程中是否已经加锁 多线程种调用fork创建子进程,子进程会继承父进程的锁的状态,父进程中所有的对锁的的操作都不能影响子进程的锁的状态。就会出现死锁,所以在多线程中执行fork之前,需要调用pthread_atfork方法,保证继承的锁绝对是解锁状态

pthread_atfork是一个注册方法,注册了三个函数,这三个函数在不同时间执行 atfork注册的三个方法,以及其调用时机,都是为了保证在fork执行过程中,所有的锁都是枷锁状态,没有其他线程会加锁成功。fork完成之后,分别在父进程空间和子进程空间解锁,fork之后,父进程的使用的锁都是解锁状态的

最新回复(0)