linux-----进程||线程控制编程

一 进程的基本概念


1.1 什么是进程?
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,
是系统进行资源分配的最小单位,是操作系统结构的基础。
在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;
在当代面向线程设计的计算机结构中,进程是线程的容器。
程序是指令、数据及其组织形式的描述,进程是程序的实体。
1.2 进程 程序的区别
程序:所编写的代码
进程:程序执行的一次过程
1.3 进程的调度(操作系统的上下文切换机制)
    1> 单核cpu一个时刻只能执行一个进程
        见图 时间片轮询.png
1.4 进程的状态
    三大状态:就绪态 运行态 阻塞态
    见图:进程的状态.png
1.5 进程的相关概念
    1>  每个进程在启动初期,操作系统都会为其开辟一个0~4G的虚拟空间
        其中0~3G为用户空间,3-4G称为内核空间(也称为进程的共享空间-->后序进程间通信使用)
        进程启动后,每个进程会将其所有的信息放在PCB进程控制块
        进程控制块:pc程序计数器,进程的状态,进程ID,堆栈信息等
    2>  操作系统启动处理,会先启动三个进程:
        0:负责引导操作系统的启动,同时创建出1号和2号进程
        1:负责硬件资源的分配以及回收资源(后序的孤儿进程的资源由其回收)
        2:负责软件资源的分配
1.6 进程的相关命令
【1】pstree
    功能:将进程以树的形式显示
    属性:-p:显示进程号
【2】ps
    属性:-ef:显示当前的父子进程关系
    PID:当前进程的ID号
    PPID:当前进程父进程的ID号
        edu118@ubuntu:~/230529/day6$ ps -ef
        UID        PID  PPID  C STIME TTY          TIME CMD
        root         1     0  0 02:36 ?        00:00:04 /sbin/init splash
        root         2     0  0 02:36 ?        00:00:00 [kthreadd]
    
    属性:-aux:显示当前进程的状态
        edu118@ubuntu:~/230529/day6$ ps -aux
        USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
        root         1  0.0  0.1 185568  6180 ?        Ss   02:36   0:04 /sbin/init splash
        root         2  0.0  0.0      0     0 ?        S    02:36   0:00 [kthreadd]
    进程的状态:
        S:休眠态
        R:运行态
        T:停止态
        I:空闲态
        Z:僵尸态
        
        s:会话首进程
        <:优先级高的进程
        l:该进程中包含线程
        +:前台进程
        N:优先级低的进程
    属性:-ajx :查看家族关系    
    PPID:父进程
    PID :当前进程号
    PGID:进程组ID
    SID : 会话ID
        edu118@ubuntu:~/230529/day6$ ps -ajx
        PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
        0     1     1     1 ?           -1 Ss       0   0:04 /sbin/init splash
        0     2     0     0 ?           -1 S        0   0:00 [kthreadd]
【3】top
功能:主要用于查看当前cpu占用率

【4】jobs
    1> ctrl + z:将程序暂停到后台
            edu118@ubuntu:~/230529/day6$ ./10-cpu 
            ^Z
            [1]+  已停止               ./10-cpu
    2> fg:将后台暂停的进程恢复到前台运行
    3> fg + %序列号 将指定的后台暂停的进程恢复到前台运行

    4> bg:将后台暂停的进程恢复到后台运行
    5> bg + %序列号:将指定的后台暂停的进程恢复到后台运行
     可执行文件 + &:将进程在后台执行
     
1.7 写时拷贝技术
    在Linux程序中,fork()会产生一个和父进程相同的进程,但子进程之后多会exec调用,
    处于效率考虑,Linux也使用了“写时拷贝技术”,也就是只有进程空间的各段内容发生变化时,
    才会将父进程的内容复制一份给子进程。
        1> 主进程修改进程空间的值
        2> 子进程使用进程空间的值
    那么就会有这样的疑问:子进程的物理空间没有代码,怎么执行exec系统调用呢?
    在执行fork之后、exec之前,两个进程使用的是相同的物理地址空间,
    子进程的代码段、数据段、堆栈都是指向父进程的物理地址空间,
    也就是说,两者的虚拟地址空间不同,但其对应的物理空间是相同的。
    当父子进程有更改相应段的行为发生时,再为子进程相应的段分配物理空间。
1.8 文件共享技术
    当在fork之前打开一些文件,那么所有的进程会共享这些文件的读写指针,
    也就是说其他进程读写文件时,其他进程可能会对其造成读写指针的偏移。
    

1.9 进程相关的API
【1】fork函数
头文件:#include <unistd.h>
原型:pid_t fork(void);
功能:创建一个子进程
参数:无
返回值:
成功:
    返回给父进程:子进程的ID号
    返回给子进程:0
失败:返回给父进程:-1
      没有子进程创建

 

 

 

 

作业:使用两个进程去拷贝同一个文件

 getpid用法

 僵尸进程

 

 

 

整形提升(面试)

 

 线程

线程间通信

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

一 线程


1.1 线程的基本概念
    线程被称为资源调度的最小单位,而进程是资源分配的最小单位
    线程不能独立存在,他是进程一部分,在进程中,主进程又称为
    主线程,所以说一个进程是由线程+进程资源组成的,一个进程下
    可能会有多个线程,那么这些线程共享进程的资源(静态区,堆区等)
    线程也可以拥有自己的资源(栈区),除了这些之外
    线程也拥有自己的线程控制块:pcb程序计数器,线程号,堆栈等信息。
    所以说,线程又被称为轻量级的进程。
1.2 线程的优势(相比于进程)
        1.内存开销更小,线程间通信方便
    线程的缺点
        1.由于资源共享(临界资源),存在资源不同步的风险
        2.线程是不安全的,一旦一个线程崩溃,那么所有的线程都会崩溃
        3.一旦主进程执行结束,那么所有的线程资源将全部释放
1.3 线程相关的API
【1】pthread_create
头文件:#include <pthread.h>      
原型:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
功能:创建一个线程
参数:
    thread:  获取线程号
    attr:    线程的属性(默认是非分离属性)
    void *(*start_routine) (void *):线程执行函数
    arg:用于线程间通信
返回值:
    成功:返回0
    失败:返回错误码

练习:创建2个线程A和B,A和B各拥有500000元,设置一个全局变量sum,将A和B的资产
       一个一个累加给全局变量,要求最后全局变量sum拥有1000000元。
【2】pthread_self
头文件:#include <pthread.h>      
原型:pthread_t pthread_self(void);
功能:获取当前线程的线程号
参数:无
返回值:返回当前线程的线程号
【3】pthread_exit
头文件:#include <pthread.h>
原型:void pthread_exit(void *retval);
功能:主动退出当前线程
参数:retval:线程退出的状态
返回值:无
【4】pthread_join
头文件:#include <pthread.h>      
原型:int pthread_join(pthread_t thread, void **retval);
功能:阻塞等待回收指定的线程
参数:thread:目标回收线程号
      retval: 目标线程结束时,返回的状态值
返回值:成功:返回0    
        失败:返回错误码

返回值也可以返回数据


【5】pthread_detach
头文件:#include <pthread.h>      
原型:int pthread_detach(pthread_t thread);
功能:将目标线程设置为分离属性(线程结束后,操作系统会自动回收其资源)
(注意:1.pthread_join会回收失败)
(      2.pthread_detach函数尽量在线程函数中使用,因为其是非阻塞函数)
参数:thread:目标线程号
返回值:
    成功:返回0
    失败:返回错误码

二 线程的同步和互斥


0 前提
    1> 临界资源:共享资源
    2> 临界区:操作共享资源的代码
    3> 原子操作:所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,
                就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。

    4> 同步和互斥的概念:
        同步就是让线程按照一定的顺序去执行
        互斥就是保证多个线程在同一个时刻只能有一个线程执行
        同步一定互斥,互斥不一定同步
2.1 线程同步---信号量
    信号量又称为无名信号量(信号灯)
【1】sem_init
头文件:#include <semaphore.h>     
原型:int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化一个信号灯
参数:
    sem:目标信号灯
    pshared:0: 线程间同步
            非0:进程间同步
    value:信号量的资源(二值信号量中 1:有资源 0:没有资源)
返回值:
    成功:返回0
    失败:返回-1

【2】sem_wait
头文件:#include <semaphore.h>    
原型:int sem_wait(sem_t *sem); 
功能:阻塞等待申请资源(-1,p操作)
参数:
    sem:目标信号灯
返回值:
        成功:返回0
        失败:返回-1
【3】sem_post
头文件:#include <semaphore.h>   
原型:  int sem_post(sem_t *sem);
功能:释放信号量的资源(+1,v操作)
参数:sem:目标信号灯
返回值:
    成功:返回0
    失败:返回-1
【4】sem_destroy
头文件:#include <semaphore.h>
原型:int sem_destroy(sem_t *sem);
功能:释放信号量资源
参数:sem:目标信号灯
返回值:
    成功:返回0
    失败:返回-1

练习:创建A B C三个线程,分别让A,B,C线程顺序执行,A线程打印A,
      B线程打印B,C线程打印C
      
2.2 线程的互斥---互斥锁
    互斥锁是一种互斥机制,它能保证上锁的部分
    多个线程在同一个时刻只能有一个线程执行
【1】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    
        失败:返回错误码
注意:一个线程可以被多把锁锁住,但是2把以上的锁容易产生死锁

【2】pthread_mutex_lock
头文件:#include <pthread.h>
原型:int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:阻塞给临界资源加锁(阻塞等待获取锁资源)
参数:
    mutex:目标锁
返回值:成功:返回0    
        失败:返回错误码

【3】pthread_mutex_trylock
头文件:#include <pthread.h>
原型:int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:非阻塞给临界资源加锁(如果获取不到锁资源,则立刻返回)
参数:
    mutex:目标锁
返回值:成功:返回0    
        失败:返回错误码

【4】pthread_mutex_unlock
头文件:#include <pthread.h>
原型:int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁
参数:
    mutex:目标锁
返回值:成功:返回0    
        失败:返回错误码
【5】pthread_mutex_destroy
头文件:#include <pthread.h>
原型:int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁一把锁
(注意:如果锁正在被使用,或者条件变量正在尝试获取,则会销毁失败)
参数:
    mutex:目标锁
返回值:成功:返回0    
        失败:返回错误码
练习:一共有100张电影票,5个人同时卖,要求创建5个线程,并且卖出的票不能
      重复,要求打印出是哪个线程卖出的第几张票。(互斥锁)
      
2.3 线程的互斥---读写锁
 1> 概念
    读写锁分为两个部分:读状态和写状态
    当处于读状态时:多个线程可以同时获取这把锁
    当处于写状态时:和互斥锁功能类似,只能有一个线程拥有这把锁
    读锁和写锁是分开加锁,但是销毁锁,不区分读或者写
 2> 使用场景
    当读任务非常多时,那么使用读写锁会大大提高程序效率。
 3> API
【1】pthread_rwlock_init
头文件:#include <pthread.h>
原型: int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
           const pthread_rwlockattr_t *restrict attr);
功能:初始化一把读写锁
参数:
    rwlock:目标读写锁
    attr:属性,默认写为NULL
返回值:成功:返回0    
        失败:返回错误码
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; //静态初始化一把读写锁
【2】pthread_rwlock_rdlock
头文件:#include <pthread.h>
原型: int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
功能:阻塞给临界资源加读锁(阻塞等待获取读锁资源)
参数:
    rwlock:目标读写锁
返回值:成功:返回0    
        失败:返回错误码
        
【3】pthread_rwlock_wrlock
头文件:#include <pthread.h>
原型: int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
功能:阻塞给临界资源加写锁(阻塞等待获取写锁资源)
参数:
    rwlock:目标读写锁
返回值:成功:返回0    
        失败:返回错误码
【4】pthread_rwlock_unlock
头文件:#include <pthread.h>
原型: int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
功能:释放锁(读锁或者写锁)
参数:
    rwlock:目标读写锁
返回值:成功:返回0    
        失败:返回错误码
【5】pthread_rwlock_destroy
头文件:#include <pthread.h>
原型: int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
功能:销毁一把读写锁
参数:
    rwlock:目标读写锁
返回值:成功:返回0    
        失败:返回错误码

2.4 死锁
    死锁是指两个或多个线程或进程在互相等待对方释放资源的情况下无法继续执行的状态。
在死锁中,每个线程都在等待其他线程释放资源,导致所有线程都无法继续执行,形成了循环等待的局面。
死锁的发生通常需要满足以下四个条件,也称为死锁的必要条件:
1. 互斥条件:资源只能被一个线程或进程占用,不能同时被多个线程或进程占用。
2. 请求与保持条件:线程或进程已经持有了至少一个资源,并且在等待其他资源。
3. 不可剥夺条件:线程或进程已经获得的资源不能被其他线程或进程强制剥夺。
4. 循环等待条件:存在一个线程或进程的资源请求序列,使得每个线程或进程都在等待下一个线程或进程所持有的资源。
要避免死锁的发生,可以采取以下措施:
1. 避免使用多个锁:尽量减少使用多个锁,或者使用更高级别的锁来代替多个低级别的锁。
2. 统一加锁顺序:确保所有线程或进程在获取锁时按照相同的顺序获取,避免出现循环等待的情况。
3. 使用超时机制:在获取锁的过程中,设置超时机制,如果超过一定时间未能获取到锁,则放弃当前操作,释放已经获取的资源。
4. 死锁检测与恢复:可以通过死锁检测算法来检测死锁的发生,并采取相应的恢复措施,例如终止某个线程或进程,释放其占用的资源。
5. 合理规划资源分配:在设计系统时,合理规划资源的分配,避免出现资源不足的情况,从根本上避免死锁的发生。
总之,死锁是多线程或多进程编程中常见的问题,需要合理设计和管理资源的分配,以及采取相应的措施来避免和解决死锁的发生。

2.5 线程的同步---条件变量
    1> 概念
        条件变量也是线程同步的机制之一,信号量使得多个线程
        可以按照固定的顺序执行,条件变量可以使线程按照用户
        自定义的逻辑顺序执行。
    2> 如何使用
        条件变量通常和互斥锁一起使用的,当唤醒一个线程后,
        线程并不是立即执行,而是需要在唤醒后,抢到锁资源
        才能执行临界资源。
    3> API
【1】
头文件:#include <pthread.h>
原型: int pthread_cond_init(pthread_cond_t *restrict cond,
           const pthread_condattr_t *restrict attr);
功能:初始化一个条件变量
参数:
    cond:目标条件变量
    attr:属性,默认写为NULL
返回值:成功:返回0    
        失败:返回错误码
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //静态初始化条件变量

【2】pthread_cond_signal
头文件:#include <pthread.h>
原型: int pthread_cond_signal(pthread_cond_t *cond);
功能:唤醒任意一个线程
参数:
    cond:目标条件变量
返回值:成功:返回0    
        失败:返回错误码
【3】pthread_cond_broadcast
头文件:#include <pthread.h>
原型: int pthread_cond_broadcast(pthread_cond_t *cond);
功能:唤醒所有线程
参数:
    cond:目标条件变量
返回值:成功:返回0    
        失败:返回错误码
【4】pthread_cond_wait
头文件:#include <pthread.h>
原型: int pthread_cond_wait(pthread_cond_t *restrict cond,
           pthread_mutex_t *restrict mutex);
功能:释放锁资源,并且将线程挂起,等待信号的到来
参数:
    cond:目标条件变量
    mutex:目标锁
返回值:成功:返回0    
        失败:返回错误码
【5】pthread_cond_destroy
头文件:#include <pthread.h>
原型: int pthread_cond_destroy(pthread_cond_t *cond);    
功能:销毁条件变量
参数:cond:目标条件变量
返回值:成功:返回0    
        失败:返回错误码
    
作业:一共有1000张电影票,5个人同时卖,要求创建5个线程,前200张票只能由A线程卖(互斥锁)
      后200张由B和C同时卖,最后600张5个线程一起卖。(条件变量+ 互斥锁)
 

管道

 

 

 

 进程间通信

一 进程间通信


1.1 概念
    进程间由于其资源都是相互独立的,所以想要实现进程间通信
    就必须找到他们共享的资源(内核资源),通过读写内核资源
    来实现,进程间的通信
1.2 分类
    1> 传统通信方式
        无名管道
        有名管道
        信号
    2> IPC第五代通信
        消息队列
        共享内存
        信号量
        套接字(网络通信)
1.3 前提
    1> 单工:通信双方,一方只能接收,另一方只能发送
    2> 半双工:通信双方,同一时刻,一方只能接收,另一方只能发送
    3> 全双工:通信双方,同一时刻,双方既能接收也能发送消息
1.4 无名管道
1> 概念
    (1)无名管道是一种用于亲缘间进程的半双工通信方式。
    (2)无名管道文件创建后,其是一个特殊的文件,在文件系统中
       没有实质文件的体现.
    (3)无名管道的大小为64k(64*1024)个字节,一旦写满后,再往管道中
       写数据,会造成write函数阻塞,当管道写满后,至少从管道中读取4k个数据后
       才能继续向管道中写数据.
    (4)当读端关闭,继续往管道中写数据,会造成"管道破裂"(程序异常退出)
    (5)当写段关闭,继续从管道中读数据,read函数会直接返回,
       写数据,write函数返回-1。
    (6)管道符合先进先出的原则,数据读走后就会消失。
2> API
【1】pipe
头文件:#include <unistd.h>
原型:int pipe(int fildes[2]);
功能:创建一个无名管道
参数:fildes:文件描述符集合
          读端:fildes[0]
          写端:fildes[1]
返回值:
    成功:返回0
    失败:返回-1

练习:实现父子间进程通信,父子间进程可以互发消息
提示:
    1.创建一个子进程
    2.创建两个管道

1.5 有名管道
 1> 概念
    (1)有名管道主要用于非亲缘间进程的通信,和无名管道的性质类似
       也是一种半双工通信方式
    (2)有名管道在文件系统上有文件的体现,但是不能对管道文件
       操作读写指针的偏移。
    (3)管道文件不是真正的文件,在不是在磁盘上进行存储,而是
        在内存中进行存储,也就是说,当进程结束后,管道文件中的
        数据将全部丢失。
    (4)有名管道的读端和写端默认都是关闭的,需要手动打开
    (5)有名管道当其读写端有一端没有打开时,open函数会阻塞等待另外
        一端的打开。
 2> API
【1】mkfifo
头文件:#include <sys/types.h>
       #include <sys/stat.h>
原型:int mkfifo(const char *pathname, mode_t mode);
功能:创建一个有名管道文件
(注意:mkfifo也可以当作命令使用)
(使用方法:mkfifo + pathname)
参数:
    pathname:路径和名称
    mode:权限 --->0664
返回值:
    成功:返回0
    失败:返回-1

练习:利用有名管道实现两个非亲缘进程(两个.c文件)的互消息
      要求进程A可以连续给进程B发消息。
提示:
    1.创建两个有名管道
    2.每个进程再创建一个子进程(或者线程)

作业:利用有名管道实现两个非亲缘进程(两个.c文件)的互发消息
      要求进程A可以连续给进程B发消息。
提示:
    1.创建两个有名管道
    2.每个进程再创建一个子线程(多线程)

1.6 进程间通信---信号
    1> 概念
    (1)信号是软件层对硬件层中断的一种模拟,是一种优先级高信号是软件层对硬件层中断的一种模拟,是一种优先级高
    的代码中断事件
    (2)信号的分类
         1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
         6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
        11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
        16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
        21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
        26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
        31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
        38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
        43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
        48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
        53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
        58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
        63) SIGRTMAX-1    64) SIGRTMAX            
    (3)信号的处理方式:
        <1> 忽略:将这个信号忽略,不处理
        <2> 捕捉:当信号触发后,执行特定注册好的程序
        <3> 默认:不特殊处理,执行默认功能
        注意:某些信号无法被忽略或者捕捉:例如:SIGKILL
    2> API
【1】signal
头文件:#include <signal.h>
//函数指针函数
原型:void ( *signal(int sig, void (*func)(int)) )(int); 
功能:处理(注册)一个信号
参数:
    sig:信号值:64个

    void (*func)(int):处理方式
        SIG_IGN:忽略
        SIG_DFL:默认
        当触发信号后,调用信号处理函数:捕捉
返回值:成功:返回上一次信号处理的值
        例如:上一次处理的是捕捉,则这一次signal的结果为上次捕捉的函数
              上一次处理为忽略或者默认你,则这一次signal成功返回0
        失败:返回SIG_ERR
练习:完成父进程回收子进程的最佳处理方式(mkfifo程序)

【2】alarm
头文件:#include <unistd.h>
原型:unsigned int alarm(unsigned int seconds); 
功能:alarm()以秒为单位将SIGALRM信号传递给调用进程。
参数:
    seconds:单位:秒
返回值:返回定时器剩余的秒数
        
注意:1> 如果seconds为零,则取消所有挂起的alarm。
      2> 在任何情况下,任何先前设置的alarm()都被取消。

1.7 IPC第五代通信---->消息队列
1>概念
    (1)消息队列用一种可用于非亲缘间的全双工通信方式,消息队列中
       是以链队列的形式保存数据,当我们将数据写入消息队列后,数据并不会丢失
    (2)消息队列可以按照先进先出的原则读取数据,也可以按照用户自定义的
       的想法从队列中读取数据
       
    (3)ipcs:用于查看第五代通信属性
         edu118@ubuntu:~/230529/day10$ ipcs
            --------- 消息队列 -----------
            键        msqid      拥有者  权限     已用字节数 消息      

            ------------ 共享内存段 --------------
            键        shmid      拥有者  权限     字节     连接数  状态      
            0x00000000 557056     edu118     600        16777216   2            
            0x00000000 655361     edu118     600        524288     2          目
            0x00000000 491522     edu118     600        524288     2          目
            0x00000000 1179651    edu118     600        524288     2          目
            0x00000000 884740     edu118     600        524288     2          目
            0x00000000 983045     edu118     600        524288     2          目
            0x00000000 1081350    edu118     600        134217728  2          目
            0x00000000 1343495    edu118     600        524288     2          目
            0x00000000 1441800    edu118     600        524288     2          目
            0x00000000 1703945    edu118     600        524288     2          目
            0x00000000 1802250    edu118     600        524288     2          目
            0x00000000 1835019    edu118     600        524288     2          目
            0x00000000 18776077   edu118     600        524288     2          目
            0x00000000 18841614   edu118     600        2097152    2          目
            0x00000000 23461903   edu118     600        74184      2          目
            0x00000000 23592976   edu118     600        524288     2          目

            --------- 信号量数组 -----------
            键        semid      拥有者  权限     nsems
    (4)ipcs的属性
        -p:
        -s:
        -m:
    (5) ipcrm
        属性:
            -q:+ 消息队列ID   //删除某一个消息队列
            -s:+ 信号量集ID   //删除某一个信号量集
            -m: + 共享内存ID   //删除某一个共享内存
【1】ftok
头文件:#include <sys/types.h>
       #include <sys/ipc.h>
原型:key_t ftok(const char *pathname, int proj_id);
功能:生成一个密钥
参数:
    pathname:路径(一定要存在)
    proj_id :传一个字符(大于0)
返回值:
    成功:返回一个密钥值
    失败:返回-1
【2】msgget
头文件:#include <sys/msg.h>  
原型:int msgget(key_t key, int msgflg);
功能:创建一个消息队列
参数:
    key:ftok函数的返回值
    msgflg:
        IPC_CREAT:如果消息队列不存在,则创建之    
                   如果消息队列存在,则直接打开
    使用格式:IPC_CREAT|0664
返回值:
    成功:返回一个消息队列的ID号
    失败:返回-1
【3】msgsnd
头文件:#include <sys/msg.h>  
原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int ms
gflg);
功能:向消息队列中写数据
参数:
    msqid:目标消息队列ID号
    msgp:
        struct mymsg {
               long   mtype;       /* Message type. must > 0*/ 
               char   mtext[1];    /* Message text. 消息正文 */
           }
    msgsz:发送消息的长度
    msgflg:发送消息的方式
        IPC_NOWAIT:非阻塞
        0         :阻塞
返回值:
    成功:返回 0
    失败:返回-1        
【4】msgrcv
头文件:#include <sys/msg.h>
原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:从消息队列中读取数据
参数:
    msqid:目标消息队列ID号
    msgp:读取到的数据存放的地址:用户定义的结构体如下:
        struct mymsg {
               long   mtype;       /* Message type. must > 0*/ 
               char   mtext[1];    /* Message text. 消息正文 */
           }
    msgsz:读取最大的消息字节
    msgtyp:读取的消息的类型
            0:先进先出读取第一个消息
            >0:读取指定消息
            <0:如果msgtype小于0,则接收小于等于msgtype绝对值的最小类型的第一条消息。
    msgflg:        
        IPC_NOWAIT:非阻塞
        0         :阻塞
返回值:
    成功:返回实际读取到的字节个数
    失败:返回-1
【5】msgctl
头文件:#include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>    
原型: int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:控制消息队列
参数:
    msqid:目标消息队列ID号
    cmd:操作方式
        IPC_SET :设置消息队列中struct ipc_perm中的信息
            struct ipc_perm {
               key_t          __key;       /* Key supplied to msgget(2) */
               uid_t          uid;         /* Effective UID of owner */
               gid_t          gid;         /* Effective GID of owner */
               uid_t          cuid;        /* Effective UID of creator */
               gid_t          cgid;        /* Effective GID of creator */
               unsigned short mode;        /* Permissions */
               unsigned short __seq;       /* Sequence number */
           };

        IPC_STAT:获取消息队列struct msqid_ds中所有的信息
        IPC_RMID:用于删除目标消息队列,如果删除,第三参数写为NULL
    buf:
    struct msqid_ds {
               struct ipc_perm msg_perm;     /* Ownership and permissions */
               time_t          msg_stime;    /* Time of last msgsnd(2) */
               time_t          msg_rtime;    /* Time of last msgrcv(2) */
               time_t          msg_ctime;    /* Time of last change */
               unsigned long   __msg_cbytes; /* Current number of bytes in
                                                queue (nonstandard) */
               msgqnum_t       msg_qnum;     /* Current number of messages
                                                in queue */
               msglen_t        msg_qbytes;   /* Maximum number of bytes
                                                allowed in queue */
               pid_t           msg_lspid;    /* PID of last msgsnd(2) */
               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };

               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };
返回值:
    成功:返回0
    失败:返回-1
【6】kill
头文件:#include <sys/types.h>
       #include <signal.h>  
原型:int kill(pid_t pid, int sig);  A---B
功能:向指定的进程发送一个信号
参数:
    pid:目标进程号
    sig:信号值:10) SIGUSR1  12) SIGUSR2
返回值:
    成功:返回0
    失败:返回-1
作业:使用消息队列+信号实现两个进程互发消息(可以连续接收和发送)
提示:1.创建一个消息队列
      2.使用两种消息类型进行收发消息
      3.使用信号发送给另一个进程,提示另一个进程接收消息
      4.通信前先将自己的进程号发送给对端

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

消息队列加信号

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值