Some little questions

本文详细介绍了进程间通信的各种方法,如管道、命名管道、信号、消息队列、共享内存、信号量和套接字,以及它们的特点和应用场景。还讨论了线程间的通信同步机制,包括自旋锁和互斥锁,以及TCP和UDP的区别。最后提到了快速排序算法的实现。

操作系统问答

进程间通讯方式

1.管道:

    管道是一种半双工的通信方式,可以在父子进程或者是兄弟进程之间进行通信。

2.命名管道:

    也称FIFO(First in first out),是一种特殊的文件,可以在不相关的进程之间通信。

3.信号:

    信号是一种异步通信方式,用于通知接收进程发生了某件事

4.消息队列:

    消息队列是一种存放在内核中的消息链表,通过消息标识符进行通信。

5.共享内存:

    共享内存是一种高效的进程间通信方式,多个进程可以直接访问同一块内存区域,避免了数据的复制。

6.信号量:

    信号量是一个计数器,用于控制对共享资源的访问,可以防止多个进程同时访问共享资源。

7.套接字:

    套接字是一种用于网络通信的通信机制,可以在不同主机之间进行进程间通信。
// shm demo
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>

#include <iostream>

using namespace std;

int main() {
    // create shm
    int shmId = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666);
    if (shmId == -1) {
        cerr << "Failed to create shared memory." << endl;
        return -1;
    }

    int* sharedDate = (int*)shmat(shmId, nullptr, 0);
    if (sharedDate == (int*)-1) {
        cerr << "Failed to attach shared memory." << endl;
        return -1;
    }

    *sharedDate = 42;

    // create child pid
    pid_t pid = fork();
    if (pid == -1) {
        cerr << "Failed to fork." << endl;
    }
    if (pid == 0) {
        // child
        cout << "Child process: get Shared data is " << *sharedDate << endl;

        // child write data to shm
        *sharedDate = 100;
        // del link
        shmdt(sharedDate);
    } else {
        // father
        // wait child
        wait(nullptr);

        cout << "Parent process: get Shared data is " << *sharedDate << endl;
        // del link
        shmdt(sharedDate);

        // del shm
        shmctl(shmId, IPC_RMID, nullptr);
    }

    return 0;
}

共享内存:

    是一种高效的通信方式,相对于其他通信方式有一下特点:
1.速度快:
    共享内存直接在京城见共享内存区域,无需进行数据的拷贝,因此速度非常快,适用于大量数据的传输。
2.低延迟:
    由于共享内存通信直接操作内存,无需进行序列化和反序列化的过程,因此通信延迟低。
3.高吞吐量:
    共享内通信可以实现高吞吐量的数据传输,特别适用于需要频繁,大量数据交换的场景。
4.无需内核参与:
    共享内存通信通过内存进行数据交换,不需要内核的参与,因此减少了系统调用和内核态与用户态的切换。
一些局限性
1. 进程间同步:
    由于多个进程可以同时访问共享内存,需要使用额外的同步机制(如信号量,互斥锁等)来确保数据的一致性和避免竞态条件。
2. 进程间协作:
    共享内存通信只提供了数据的交换机制,而没有提供进程间的协作机制,因此需要借助其他机制来进行进程间的协调和同步。信号量,条件变量等

多线程的通讯和同步异步方式

1.共享内存:

多个线程可以通过访问共享的内存区域进行通信。线程可以读取和写入共享内存中的数据进行数据交换。为了保证线程安全需要使用同步机制,如互斥锁(mutex)或读写锁(read write lock)
来控制对共享内存的访问

2.消息队列:

多个线程可以通过消息队列进行通信。线程可以将消息发送到队列中,其他线程可以从队列中获取消息并进行处理。消息队列可以实现异步通信,发送方不需要等待接收方立即处理,提高了系统的并发性能。

3.信号量:

信号量是一种同步机制,用于控制多个线程之间的访问权限。线程可以通过信号量来进行同步和互斥操作。例如,可以使用信号量来限制同时访问共享资源的线程数

4.条件变量:

条件变量用于线程之间的通信和同步。一个线程可以等待某个条件变量满足,而另一个线程可以在满足条件时通知等待的线程。条件变量常用于生产者-消费者模型等场景。

5.Futures和Promises:

Futures(未来)和Promises(承诺)是一种异步编程模型,多个线程可以通过Futures和Promises来进行通信和同步。一个线程可以在Promise中设置结果,而其他线程可以使用Future来等待结果。

6.回调函数:

多线程可以通过回调函数进行通信。一个线程可以在某个事件发生时调用注册的回调函数,而其他线程可以在回调函数中处理相应的逻辑

线程 joinable 状态和 unjoinable 状态

1. joinable:

当创建一个线程时,它通常处于joinable转态
在joinable状态下,主线程可以调用join()或者detach()来控制线程的执行和资源释放
如果主线程调用detach()来分离子线程,主线程将不再与子线程关联,子线程将成为一个独立执行的线程

2. unjoinable:

在线程已经被join()或者detach()它进入unjoinable状态
在unjoinable状态下,线程无法再调用join()或者detach()来控制线程的执行和资源的释放
如果主线程试图调用join()来等待一个unjoinable状态的线程,会抛出system_error异常

程序编译的过程:

1.预处理

gcc -E main.c -o main.i
预处理对源代码进行处理,主要包括宏展开,头文件包含等操作
预处理的结构是一个被修改过的源码文件,通常以 .i或者 .ii为扩展名

2.编译

gcc -S main.i -o main.s
编译器将预处理后的源代码翻译成汇编代码
编译器进行词法分析,语法分析,语义分析,优化等操作
编译的结果是一个汇编文件,通常以 .s为扩展名

3.汇编

gcc -c main.s -o main.o
汇编器将汇编代码翻译成机器指令
汇编器将汇编代码中的每一天指令映射成对应的机器码
汇编的结果是一个可重定位目标文件,通常以 .o或者.obj 为扩展名

4.链接

gcc main.o -o main
链接器将目标文件以及其他库文件进行链接,生成最终可执行文件
链接器将目标文件引用的函数和变量与其他目标文件或库文件中的定义进行关联
链接的结果是一个可执行文件,可以直接运行

堆和栈的区别

堆和栈是计算机内存中的两种不同的分配方式,他们有不同的特点和用途:

1.存储数据类型

堆:
    主要用于存储动态分配的数据,如对象和数据结构。堆中的数据可以在程序运行时动态分配和释放,通常由开发者显式地管理内存。
栈:
    主要用于存储程序执行过程中的函数调用和局部变量,栈中的数据是有限的,具有固定的生命周期,通常由编译器和运行系统自动管理。

2.内存管理

堆:
    内存分配和释放在堆中通常是显式的,开发者需要手动分配内存,同时也需要负责释放不再需要的内存,以避免内存泄漏
栈:
    栈内存的分配和释放是隐式的,有编译器和运行时系统管理,当一个函数调用结束时,栈上的局部变量会被自动释放。

3.数据访问速度

堆:
    堆内存的访问速度相对较慢,因为动态分配的内存需要查找并分配合适的内存块
栈:
    栈内存的访问速度相对较快,因为栈上的数据结构通常具有固定大小,并且可以直接通过指针来访问。

4.存储限制

堆:
    堆的大小通常受制于物理内存的大小,他可以动态增长,但可能会受到系统资源的限制
栈:
    栈的大小通常是有限的,受到编译器和操作系统的限制,通常不太适合存储大型数据结构。

进程和线程的区别

1.定义

进程:
    进程是程序的一次执行实例,它具有独立的内存空间,文件系统和系统资源。每个进程都有自己的地址空间,他们之间又相互独立。
线程:
    线程是进程内的执行单元,多个线程可以共享一个进程的内存空间和系统资源。线程之间更轻量级,因为他们共享进程资源。

2.资源消耗

进程:
    每个进程都有自己的独立内存空间,因此进程之间的资源消耗相对较大。
线程:
    线程共享进程的内存空间,因此线程之间的资源消耗相对较小。

3.通信和同步

进程:
    进程之间的通信相对较复杂,通常需要使用进程间通信,如管道,消息队列,共享内存,信号,套接字等,进程之间的同步也需要额外的同步机制。
线程:
    线程之间可以更容易地共享数据,通常通过共享内存来实现,也可以使用线程同步机制,如互斥锁,信号量,条件变量等

4.创建和销毁

进程:
    创建和销毁进程的开销较大,因为他们需要分配和释放独立的内存空间
线程:
    创建和销毁线程的开销较小,因为他们共享进程的资源

5.安全性

进程:
    由于进程之间相互隔离,一个进程的崩溃通常不会影响其他进程
线程:
    现成之间共享进程的内存空间,因此一个线程的错误可能会影响整个进程

6.并行性

进程:
    多个进程可以并行执行,因为他们在不同的地址空间,但并行进程之间的通信和同步较为复杂
线程:
    多个线程可以在同一个进程并执行,因为他们共享相同的地址空间,通信和同步相对容易

自旋锁和互斥锁的区别

1.阻塞和忙等待

互斥锁:
    当一个线程尝试获取一个已被其他线程持有的互斥锁时,他会被阻塞,直到锁可以使用。这意味着线程会进入休眠状态,不再占用CPU资源
自旋锁:
    当一个线程尝试获取一个已被其他线程持有的自旋锁时,他会忙等待,即反复检查锁是否可用。线程不会放弃CPU资源,而是持续检查,直到获取锁。

2.CPU资源占用

互斥锁:
    互斥锁的阻塞模式意味着线程在等待锁时不会占用CPU资源,因此在多线程应用中,他可以有效减少CPU资源浪费
自旋锁:
    自旋锁在忙等待期间会持续占用CPU资源,可能会导致CPU资源浪费,特别是在高并发情况下

3.使用场景

互斥锁:
    适用于低竞争情况下,当锁的竞争频率较低时,互斥锁通常更高效
自旋锁:
    适用于高竞争情况下,当锁的竞争频率较高时,自旋锁可能比互斥锁更高效,因为他避免了线程切换的开销

4.实现方式

互斥锁:
    通常由操作系统内核提供的原语来实现,可以利用操作系统的调度器进行线程阻塞和唤醒
自旋锁:
    通常是通过原子操作实现,它使用硬件原语来实现忙等待,而不是依赖操作系统的调度器

TCP和UDP的区别

1.连接性

TCP:
    TCP是面向连接的协议,使用三次握手建立连接,然后在数据传输完毕后使用四次挥手关闭连接
UDP:
    UDP是无连接的协议,发送方和接收方在通信前不需要建立连接,也不需要维护连接状态

2.可靠性

TCP:
    TCP提供可靠的数据传输,通过确认和重传机制来保证数据的可靠性
UDP:
    UDP不提供数据包的确认和重传机制,因此无法保证数据的可靠性

3.有序性

TCP:
    TCP保证数据的有序性,发送的数据包会按照发送的顺序一次到达接收方
UDP:
    UDP不保证数据的有序性,发送的数据包可能以不同的顺序到达接收方

4.拥塞控制

TCP:
    TCP具有拥塞控制机制,通过动态调整发送速率来避免网路拥塞
UDP:
    UDP没有拥塞控制机制,发送方可以以任意速率发送数据,因此容易引起网络拥塞

5.开销

TCP:
    TCP的开销较大,因为它需要维护连接状态,实现可靠性和有序性等机制
UDP:
    UDP的开销较小,因为它没有连接状态和可靠性机制

6.使用场景

TCP:
    由于TCP的可靠性和有序性,适用于需要确保数据完整,按顺序到达的应用,比如网页浏览,文件传输
UDP:
    UDP适用于实时性要求较高,对可靠性要求相对较低的应用,比如实时游戏,音视频传输等

快速排序

void quickSort(vector<int>& arr, int left, int right){
    if(left >= right){
        return;
    }
    int pivot = arr[left];
    int low = left;
    int high = right;
    while(low < high){
        while(low < high && arr[high] >= pivot){
            high--;
        }
        while(low < high && arr[left] <= pivot){
            low++;
        }
    }

    swap(arr[left], arr[low]);

    quickSort(arr, left, low - 1);
    quickSort(arr, low + 1, right);

    return;
}
Demo: Exploring Data with SAS Procedures In this demonstration, we use the PRINT, MEANS, UNIVARIATE, and FREQ procedures to explore and validate our data. Reminder: If you restarted your SAS session,you must recreate the PG1 library so you can access your practice files. In SAS Studio, open and submit the libname.sas program in the EPG1V2 folder. In Enterprise Guide, run the Autoexec process flow. Note: If you did not create the libname.sas program, complete the Activity: Create a Library for This Course (REQUIRED) in Lesson 2. Open p103d01.sas from the demos folder and locate the Demo section of the program. Complete the PROC PRINT statement to list the data in pg1.storm_summary. Use the DATA= option to specify the table name. Use the OBS= option to print only the first 10 observations. Highlight the step and run the selected code. Open code or syntax in a separate window. proc print data=pg1.storm_summary (obs=10); run; Review the output. The first 10 rows are displayed and all columns are included. Let's select the columns to include, and add a comment to document the program. Add a VAR statement to include only the following columns: Season, Name, Basin, MaxWindMPH, MinPressure, StartDate, and EndDate. Enterprise Guide: To easily add column names, use the autocomplete prompts to view and select columns. You can either double-click on a column to add it in the program, or start to type the column name and press the spacebar when the correct column is highlighted. SAS Studio: To easily add column names, place your cursor after the keyword VAR. Use the Library section of the navigation pane to find the pg1 library. Expand the storm_summary table to see a list of column names. Hold down the Ctrl key and select the columns in the order in which you want them to appear in the statement. Drag the selected columns to the VAR statement. Add the comment, list first 10 rows, before the PROC PRINT statement. Highlight the step and run the selected code. Open code or syntax in a separate window. /*list first 10 rows*/ proc print data=pg1.storm_summary(obs=10); var Season Name Basin MaxWindMPH MinPressure StartDate EndDate; run; Review the output. The output contains10 rows, but we've limited the columns and changed their order in the report. Remember we're using these procedures to validate our data. As we look at the values we notice that there are missing values for Name, and that Basin includes both lowercase and uppercase NA. There are also some missing values for MaxWindMPH and MinPressure. And that's just in the first 10 rows. Let's use other procedures to validate our data. Next we'll use PROC MEANS to compute summary statistics. Copy the PROC PRINT step, paste it at the end of the program and change PRINT to MEANS Remove the OBS= data set option to analyze all observations. Modify the VAR statement to include only MaxWindMPH and MinPressure. The columns on the VAR statement must be numeric. Add calculate summary statistics as a comment before the PROC MEANS statement. Highlight the step and run the selected code. Open code or syntax in a separate window. /*calculate summary statistics*/ proc means data=pg1.storm_summary; var MaxWindMPH MinPressure; run; Review the output. The report includes basic summary statistics for these two numeric columns. The frequency count, N, has different values for each column. This indicates that there are quite a few missing values for MinPressure compared to MaxWindMPH. You might want to look at the Minimum and Maximum to see if those ranges appear valid. Six is a pretty small value for MaxWindMPH. We might want to investigate further to see if this is a valid value. And negative 9,999 is definitely not valid for MinPressure. Next we'll use PROC UNIVARIATE to compute summary statistics including the 5 extreme low and high values. Copy the PROC MEANS step, paste it at the end of the program, and change MEANS to UNIVARIATE. Add examine extreme values as a comment before the PROC UNIVARIATE statement. Highlight the step and run the selected code. Open code or syntax in a separate window. /*examine extreme values*/ proc univariate data=pg1.storm_summary; var MaxWindMPH MinPressure; run; Review the output. Scroll down to the Extreme Observations table. It includes the observation number and the value for the low and high MaxWindMPH values. We might be interested later on in learning which storm had a maximum wind speed of 213 miles per hour. Scroll down to the Extreme Observations report for MinPressure. There are only two rows where the value for MinPressure was negative 9,999. That gives us a little more insight as to what we're dealing with in our data. Let's use PROC FREQ to generate one-way frequency reports. Copy the PROC UNIVARIATE step and paste it at the end of the program. Copy the PROC UNIVARIATE step, paste it at the end of the program, and change UNIVARIATE to FREQ. Change the VAR statement to a TABLES statement to produce frequency tables for Basin, Type, and Season. Add list unique values and frequencies as a comment before the PROC FREQ statement. Highlight the step and run the selected code. Open code or syntax in a separate window. /*list unique values and frequencies*/ proc freq data=pg1.storm_summary; tables Basin Type Season; run; Review the output. Recall that our PROC PRINT output showed that there were some lower case values for Basin. The Frequency table for Basin indicates that 16 rows have a lowercase na value. We'll need to correct that later on. The Type frequency table shows no case inconsistencies or incorrect values. The frequency table for Season shows how many storms there were per season. We can identify those seasons that had the most storms, such as 2005 with 102. These procedures give us insight to our data. They help us to learn about the data values and what we may need to fix as we prepare our data. They also help us think about questions we may want to answer as we analyze our data further.
09-06
### PRINT程序 `PROC PRINT` 主要用于查看数据。它可以简单地将数据集中的观测值打印出来,帮助直观查看数据内容。 ```sas PROC PRINT DATA = your_dataset; RUN; ``` 上述代码直接打印出 `your_dataset` 数据集中的所有观测和变量。若只想查看部分变量,可以使用 `VAR` 语句指定: ```sas PROC PRINT DATA = your_dataset; VAR var1 var2; RUN; ``` 这里仅打印 `var1` 和 `var2` 两个变量。 ### MEANS程序 `PROC MEANS` 用于计算数据的统计信息,默认会计算均值、标准差、最小值、最大值等。 ```sas PROC MEANS DATA = your_dataset; RUN; ``` 这会输出数据集中所有数值变量的基本统计信息。若要指定统计量和变量,可使用 `VAR` 和 `NWAY` 等选项: ```sas PROC MEANS DATA = your_dataset NWAY; VAR var1 var2; OUTPUT OUT = result_dataset MEAN = mean_var1 mean_var2; RUN; ``` `NWAY` 选项确保仅输出总的统计信息,`OUTPUT` 语句将结果输出到 `result_dataset` 数据集中,同时指定只计算 `var1` 和 `var2` 的均值。 ### UNIVARIATE程序 `PROC UNIVARIATE` 可进行单变量的详细统计分析,包括矩、位置和变异性的基本测度、位置检验、分位数和极端观测等 [^2]。 ```sas PROC UNIVARIATE DATA = your_dataset; VAR var1; HISTOGRAM var1 / NORMAL; PROBPLOT var1 / NORMAL (MU = EST SIGMA = EST COLOR = RED W = 2); RUN; ``` `VAR` 语句指定要分析的变量为 `var1`,`HISTOGRAM` 语句绘制 `var1` 的直方图,并与正态分布对比;`PROBPLOT` 语句绘制概率图,同样与正态分布对比,且对正态分布的均值和标准差进行估计 [^4]。 ### FREQ程序 `PROC FREQ` 用于生成频率报告,可查看分类变量的频数和百分比。 ```sas PROC FREQ DATA = your_dataset; TABLES var1; RUN; ``` `TABLES` 语句指定要分析的分类变量 `var1`,程序会输出 `var1` 各取值的频数和百分比。若要分析多个变量的交叉频率,可以使用: ```sas PROC FREQ DATA = your_dataset; TABLES var1 * var2; RUN; ``` 这将输出 `var1` 和 `var2` 的交叉频率表。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值