互斥锁/读写锁(Linux)
一、互斥锁
临界资源概念:
不能同时访问的资源,比如写文件,只能由一个线程写,同时写会写乱。
比如外设打印机,打印的时候只能由一个程序使用。
外设基本上都是不能共享的资源。
生活中比如卫生间,同一时间只能由一个人使用。
必要性: 临界资源不可以共享
两种方法创建互斥锁,静态方式和动态方式
动态方式:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
其中mutexattr用于指定互斥锁属性,如果为NULL则使用缺省属性。
静态方式:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;锁的销毁:
int pthread_mutex_destroy(pthread_mutex_t *mutex)
在Linux中,互斥锁并不占用任何资源,
因此LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。互斥锁的使用:
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)vim 设置代码全文格式化:gg=G
查看线程:
没有加互斥锁:
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>FILE* fp;void* testattr(void* arg)
{pthread_detach(pthread_self());printf("This is testattr pthread\n");char str[] = "You read testattr thread\n";char c;int i = 0;while(1){while(i<strlen(str)){c = str[i];int ret = 0;ret = fputc(c,fp);i++;usleep(1);}i = 0;usleep(1);}pthread_exit("testattr exit");
}void* testattr2(void* arg)
{pthread_detach(pthread_self());printf("This is testattr2 pthread\n");char str[] = "I write testattr2 line\n";char c;int i = 0;while(1){while(i<strlen(str)){c = str[i];int ret = 0;ret = fputc(c,fp);i++;usleep(1);}i = 0;usleep(1);}pthread_exit("testattr2 exit");
}int main()
{pthread_t pthread;pthread_t pthread2;int i = 0;void* retv;fp = fopen("1.txt","a+");if(fp == NULL){perror("fp");exit(-1);}pthread_create(&pthread,NULL,testattr,NULL);pthread_create(&pthread2,NULL,testattr2,NULL);while(1){sleep(1);}fclose(fp);return 0;
}
1.txt中的值:
加上互斥锁:
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
mutex
参数是一个指向互斥锁对象的指针,该锁对象必须是一个已经初始化的互斥锁。
pthread_mutex_lock
函数尝试对互斥锁进行加锁。如果互斥锁当前没有被锁住,那么调用将成功,该线程将对互斥锁进行加锁并立即返回。如果互斥锁当前被其他线程锁住,那么调用将被阻塞,直到互斥锁被释放。
在加锁之后,线程负责确保在对共享资源的访问完成后调用 pthread_mutex_unlock
函数进行解锁,以允许其他线程获得对互斥锁的访问。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
是一种静态初始化互斥锁的方式。
在使用互斥锁之前,必须对其进行初始化。
PTHREAD_MUTEX_INITIALIZER 是一个宏,它在编译时为互斥锁对象提供了默认的初始值。
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>FILE* fp;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* testattr(void* arg)
{pthread_detach(pthread_self());printf("This is testattr pthread\n");char str[] = "You read testattr thread\n";char c;int i = 0;while(1){pthread_mutex_lock(&mutex);while(i<strlen(str)){c = str[i];int ret = 0;ret = fputc(c,fp);i++;usleep(1);}pthread_mutex_unlock(&mutex);i = 0;usleep(1);}pthread_exit("testattr exit");
}void* testattr2(void* arg)
{pthread_detach(pthread_self());printf("This is testattr2 pthread\n");char str[] = "I write testattr2 line\n";char c;int i = 0;while(1){pthread_mutex_lock(&mutex);while(i<strlen(str)){c = str[i];int ret = 0;ret = fputc(c,fp);i++;usleep(1);}pthread_mutex_unlock(&mutex);i = 0;usleep(1);}pthread_exit("testattr2 exit");
}int main()
{pthread_t pthread;pthread_t pthread2;int i = 0;void* retv;fp = fopen("1.txt","a+");if(fp == NULL){perror("fp");exit(-1);}pthread_create(&pthread,NULL,testattr,NULL);pthread_create(&pthread2,NULL,testattr2,NULL);while(1){sleep(1);}fclose(fp);return 0;
}
1.txt中的值:
动态方式创建互斥锁:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
其中mutexattr用于指定互斥锁属性,如果为NULL则使用缺省属性。
二、读写锁
必要性:提高线程执行效率
特性:
写者:写者使用写锁,如果当前没有读者,也没有其他写者,写者立即获得写锁;否则写者将等待,直到没有读者和写者。
读者:读者使用读锁,如果当前没有写者,读者立即获得读锁;否则读者等待,直到没有写者。
注意:
同一时刻只有一个线程可以获得写锁,同一时刻可以有多个线程获得读锁。
读写锁处于写锁状态时,所有试图对读写锁加锁的线程,不管是读者试图加读锁,还是写者试图加写锁,都会被阻塞。
读写锁处于读锁状态时,有写者试图加写锁时,之后的其他线程的读锁请求会被阻塞,以避免写者长时间的不写锁
初始化一个读写锁 pthread_rwlock_init读锁定读写锁 pthread_rwlock_rdlock非阻塞读锁定 pthread_rwlock_tryrdlock写锁定读写锁 pthread_rwlock_wrlock非阻塞写锁定 pthread_rwlock_trywrlock解锁读写锁 pthread_rwlock_unlock释放读写锁 pthread_rwlock_destroy
int pthread_detach(pthread_t thread); 成功:0;失败:错误号作用:从状态上实现线程分离,注意不是指该线程独自占用地址空间。线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后(不会产生僵尸线程),其退出状态不由其他线程获取,而直接自己自动释放(自己清理掉PCB的残留资源)。网络、多线程服务器常用。
示例代码:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>pthread_rwlock_t rwlock;FILE *fp;
void * read_func(void *arg){pthread_detach(pthread_self());printf("read thread\n");char buf[32]={0};while(1){pthread_rwlock_rdlock(&rwlock);while(fgets(buf,32,fp)!=NULL){printf("%d,rd=%s\n",(int)arg,buf);usleep(1000);}pthread_rwlock_unlock(&rwlock);sleep(1);}}void *func2(void *arg){pthread_detach(pthread_self());printf("This func2 thread\n");char str[]="I write func2 line\n";char c;int i=0;while(1){pthread_rwlock_wrlock(&rwlock);while(i<strlen(str)){c = str[i];fputc(c,fp);usleep(1);i++;}pthread_rwlock_unlock(&rwlock);i=0;usleep(1);}pthread_exit("func2 exit");}void *func(void *arg){pthread_detach(pthread_self());printf("This is func1 thread\n");char str[]="You read func1 thread\n";char c;int i=0;while(1){pthread_rwlock_wrlock(&rwlock);while(i<strlen(str)){c = str[i];fputc(c,fp);i++;usleep(1);}pthread_rwlock_unlock(&rwlock);i=0;usleep(1);}pthread_exit("func1 exit");
}int main(){pthread_t tid1,tid2,tid3,tid4;void *retv;int i;fp = fopen("1.txt","a+");if(fp==NULL){perror("fopen");return 0;}pthread_rwlock_init(&rwlock,NULL);pthread_create(&tid1,NULL,read_func,1);pthread_create(&tid2,NULL,read_func,2);
sleep(1);
//读写是抢占,不是按顺序
//有时候一直在调用读,写没排上号
//谁抢上是谁,所以加上sleep(1)pthread_create(&tid3,NULL,func,NULL);pthread_create(&tid4,NULL,func2,NULL);while(1){ sleep(1);} }
-
文件和锁的初始化:
- 该程序以附加模式(
"a+"
)打开名为"1.txt"的文件,使用fopen
。如果文件不存在,它尝试创建它。 - 使用
pthread_rwlock_init
初始化读写锁。
- 该程序以附加模式(
-
线程函数:
read_func
:该函数负责从文件中读取。它不断从文件中读取行并将它们打印到控制台。它使用读锁以确保它可以与其他读取器并发读取,但在读取正在进行时不能写入。testattr
和testattr1
:这些函数不断将预定义的字符串写入文件。它们使用写锁以确保只有其中一个可以同时写入文件。
-
主函数:
- 它创建五个线程:两个用于读取(
pthread2
和pthread3
),三个用于写入(pthread
,pthread1
和主线程)。 - 主线程进入一个无限循环(
while(1)
)以使程序无限期运行。
- 它创建五个线程:两个用于读取(
-
线程分离:
- 使用
pthread_detach(pthread_self())
分离每个线程,以在线程退出时自动回收资源。
- 使用
-
线程同步:
- 读写操作由读写锁(
pthread_rwlock_rdlock
和pthread_rwlock_wrlock
)保护,以确保正确的同步并避免数据损坏。
- 读写操作由读写锁(
-
文件操作:
- 文件操作使用标准文件I/O函数(
fgets
用于读取,fputc
用于写入)。
- 文件操作使用标准文件I/O函数(
-
睡眠和延迟:
- 使用
usleep
和sleep
引入操作之间的延迟,以更好地展示并发行为。
- 使用
-
主函数中的无限循环:
- 通过带有
sleep(1)
延迟的无限循环,保持主线程处于活动状态。
- 通过带有
那读写的顺序是什么?
在这个程序中,有两个读线程 (read_func
) 和两个写线程 (testattr
和 testattr1
),以及主线程。读线程和写线程是同时运行的,并且使用了读写锁 (pthread_rwlock_t rwlock
) 来确保对文件的安全访问。
-
读线程 (
read_func
) 在一个无限循环中,通过pthread_rwlock_rdlock
获取读锁,然后通过fgets
从文件中读取内容。读操作完成后,通过pthread_rwlock_unlock
释放读锁。这表示读线程首先获取读锁,然后读取文件内容。 -
写线程 (
testattr
和testattr1
) 在一个无限循环中,通过pthread_rwlock_wrlock
获取写锁,然后通过fputc
向文件写入内容。写操作完成后,通过pthread_rwlock_unlock
释放写锁。这表示写线程首先获取写锁,然后写入文件内容。
总体而言,程序中的读线程和写线程是同时运行的,但是通过使用读写锁,可以确保对文件的安全访问,防止读和写操作之间的冲突。
注意:
读线程 (read_func) 在读取文件时获取读锁 (pthread_rwlock_rdlock),
这时其他读线程也可以同时获取读锁。
这允许多个读线程同时读取文件内容,因为读操作不会互斥。
在使用读写锁时,写线程获得写锁时会阻塞其他写线程和读线程,
以确保在写入文件时不会同时有其他线程读或写。在这个程序中,当一个线程(写线程)获得写锁时,
其他线程(包括读线程和其他写线程)都会被阻塞,直到写线程释放写锁。所以,写线程会独占地访问文件,直到它完成写入并释放写锁。
这种方式确保了写的原子性,防止多个写线程之间和读线程之间的竞争条件。
为什么需要读锁?
虽然读操作本身不会改变数据,但如果在读的同时有其他线程在写,就可能读到不一致或不准确的数据。
因此,在多线程环境下,为了确保数据的一致性,读操作也需要进行同步,而这就是使用读写锁的原因。
上述的程序中,pthread_rwlock_rdlock 用于获取读锁,而 pthread_rwlock_unlock 用于释放读锁。
这样做的目的是:通过获取读锁,确保在读取文件内容时不会被写线程中断,避免了读线程和写线程之间的竞态条件。释放读锁,以允许其他读线程或写线程访问文件。使用读写锁可以实现多个线程同时读取文件,但在写线程写入时阻塞读线程,以保证对文件的安全访问。
这种同步机制确保了对共享资源的正确和一致的访问。
为什么此代码只需要一个读的回调函数?
在这个特定的程序中,可能只需要一个读回调函数。
读回调函数负责获取读锁,读取文件内容,然后释放读锁,以确保在读的过程中其他线程不会写入文件。
由于读操作本身不修改数据,多个读线程可以并发地执行。写操作则需要更谨慎地处理,因为写线程在写入时需要独占访问,避免与其他写线程或读线程发生冲突。
因此,写回调函数需要获取写锁,执行写操作,然后释放写锁。
这里为什么需要usleep(1000)?
usleep(1000); 的目的是让读线程休眠一毫秒(1000微秒)。
这样的操作通常是为了减缓循环的执行速度,以避免过于频繁地执行文件读取操作。
usleep 函数用于在指定的微秒数内挂起当前线程的执行。
相关文章:
互斥锁/读写锁(Linux)
一、互斥锁 临界资源概念: 不能同时访问的资源,比如写文件,只能由一个线程写,同时写会写乱。 比如外设打印机,打印的时候只能由一个程序使用。 外设基本上都是不能共享的资源。 生活中比如卫生间,同一…...
Jackson序列化Bean额外属性附加--@JsonAnyGetter、@JsonUnwrapped用户
1. 场景 有一项工作,需要将数据从一个服务S中读取出来(得到的是一个JSON),将数据解析转换以后构造成一个数组的类型A的对象,写入到一个服务T中。 A.class Data public class A {String f0 ;String f1 ; }在发现需要…...
排序算法——冒泡排序算法详解
冒泡排序算法详解 1.引言2.算法概览2.1输入处理2.2核心算法步骤2.3数据结构2.4复杂度分析 3.算法优化4.边界条件和异常处理5.实验和测试6.应用和扩展7.代码示例8.总结 1.引言 冒泡排序是一种简单而直观的比较排序算法,它通过多次遍历数组,比较相邻元素并…...
宋仕强论道之华强北的缺货潮(十六)
始于2019年缺货潮让华强北又生产一大批亿万富翁,缺货的原因主要是:首先,疫情封控导致大量白领在家远程办公,需要购买电脑、打印机等办公设备,同时孩子们也要在家上网课,进一步增加对电子智能终端产品的需求…...
登录注册页面
前提:基于element-ui环境 模态登录组件 分析Login.vue <template><div class"login"><span click"handleClose">X</span></div> </template><script> export default {name: "Login",m…...
视频美颜SDK详解:动态贴纸技术的前沿探索
当下,美颜SDK的动态贴纸技术作为视频美颜的独特亮点,吸引了越来越多开发者和用户的关注。 一、技术详解 动态贴纸技术是视频美颜SDK中的一项创新性功能,它通过在实时视频中添加各种动态效果,为用户提供更加生动有趣的拍摄体验。…...
vue3 实现上传图片裁剪
在线的例子以及代码,请点击访问链接...
flink1.18 广播流 The Broadcast State Pattern 官方案例scala版本
对应官网 https://nightlies.apache.org/flink/flink-docs-master/docs/dev/datastream/fault-tolerance/broadcast_state/ 测试数据 * 广播流 官方案例 scala版本* 广播状态* https://nightlies.apache.org/flink/flink-docs-master/docs/dev/datastream/fault-tolerance…...
vueRouter中scrollBehavior实现滚动固定位置
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。 注意: 这个功能只在 HTML5 h…...
解决WinForms跨线程操作控件的问题
解决WinForms跨线程操作控件的问题 介绍 在构建Windows窗体应用程序时,我们通常会遇到需要从非UI线程更新UI元素的场景。由于WinForms控件并不是线程安全的,直接这样做会抛出一个异常:“控件’control name’是从其他线程创建的,…...
从零开始:Git 上传与使用指南
Git 是一种非常强大的版本控制系统,它可以帮助您在多人协作开发项目中更好地管理代码版本,并确保每个团队成员都能及时地获取最新的代码更改。在使用 Git 进行版本控制之前,您需要先进行一些设置,以确保您的代码能够顺利地与远程仓…...
Docker compose部署Golang服务
Docker Compose 部署 在使用docker部署时,除了使用--link的方式来关联容器之外,还可以使用 docker compose 运行多个容器。 本文以项目:https://github.com/johncxf/go-api 为例。 定义 Dockerfile 我这里用于区分默认 Dockerfile 文件&a…...
Day36 435无重叠区间 763划分字母区间
435 无重叠区间 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 注意: 可以认为区间的终点总是大于它的起点。 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。 本题与上一题类似: 如果按照左…...
【Servlet】如何编写第一个Servlet程序
个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【Servlet】 本专栏旨在分享学习Servlet的一点学习心得,欢迎大家在评论区交流讨论💌 Servlet是Java编写的服务器端…...
读懂比特币—bitcoin代码分析(五)
今天的代码分析主要是 bitcoin/src/init.cpp 文件中的三个函数:AppInitSanityChecks、AppInitLockDataDirectory、AppInitInterfaces,下面我们来说明这三个函数是用来干什么的,并逐行解读函数代码,先贴出源代码如下: …...
uniapp使用uQRCode插件生成二维码的简单使用
最近在找移动端绘制二维码的问题 ,直接上代码 下载 weapp-qrcode.js(可以通过npm install weapp-qrcode --save 下载,之后把它父子到untils目录下) npm install weapp-qrcode --save在组件页面使用 <canvas id"couponQrcode" canvas-id&qu…...
【寒假每日一题·2024】AcWing 4965. 三国游戏(补)
文章目录 一、题目1、原题链接2、题目描述 二、解题报告1、思路分析2、时间复杂度3、代码详解 一、题目 1、原题链接 4965. 三国游戏 2、题目描述 二、解题报告 1、思路分析 思路参考y总:y总讲解视频 (1)题目中的获胜情况分为三种ÿ…...
docker 安装mongodb 数据库
1.拉取mongodb镜像 docker pull mongo2.创建文件夹 mkdir -p /home/mongo/conf/ mkdir -p /home/mongo/data/ mkdir -p /home/mongo/logs/3.新增mongod.conf文件 cd /home/mongo/conf && vi mongod.confmongod.conf文件内容: # 数据库文件存储位置 dbpa…...
整数反转算法(leetcode第7题)
题目描述: 给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。假设环境不允许存储 64 位整数(有符号或无符号)。示例 1…...
微信小程序(十)表单组件(入门)
注释很详细,直接上代码 上一篇 新增内容: 1.type 属性指定表单类型 2.placeholder 属性指定输入框为空时的占位文字 源码: form.wxml <!-- 提前准备好的布局结构代码 --> <view class"register"><view class"…...
xcode 设置 ios苹果图标,为Flutter应用程序配置iOS图标
图标设置 1,根据图片构建各类尺寸的图标2.xcode打开ios文件3.xcode设置图标4.打包提交审核,即可(打包教程可通过我的主页查找) 1,根据图片构建各类尺寸的图标 工具网址:https://icon.wuruihong.com/ 下载之后文件目录如下 拷贝到项目的ios\Runner\Assets.xcassets\AppIcon.ap…...
什么是IDE?新手用哪个IDE比较好?
哈喽大家好,我是咕噜美乐蒂,很高兴又见面啦!今天我们来了解一下什么是IDE以及新手应该如何选择IDE比较合适。 一、什么是IDE? IDE(Integrated Development Environment,集成开发环境)是一种软…...
【数据库学习】pg安装与运维
1,安装与配置 #安装 yum install https:....rpm1)安装目录 bin目录:二进制可执行文件目录,此目录下有postgres、psql等可执行程序;pg_ctl工具在此目录,可以通过pg_ctl --help查看具体使用。 conf目录&…...
第二篇【传奇开心果短博文系列】Python的OpenCV库技术点案例示例:图像处理
传奇开心果短博文系列 系列短博文目录Python的OpenCV库技术点案例示例短博文系列 博文目录一、项目目标二、第一个示例代码三、第二个示例代码四、第三个示例代码五、第四个示例代码六、第五个示例代码七、知识点归纳总结 系列短博文目录 Python的OpenCV库技术点案例示例短博文…...
【vue oidc-client】invalid_requestRequest Id: 0HN0OOPFRLSF2:00000002
需求:完成统一登录,需要从三方平台跳到我们的平台。 oidc-client报错记录。这个一般是配置信息出错,需要和三方平台进行沟通,一定要把client_id,密钥进行对应; 同时关于此次出错还修改了以下代码ÿ…...
什么是中间人攻击? ssh 连接出现 Host key verification failed 解决方法
文章目录 前言known_hosts 文件是什么文件路径示例 连接出现 Host key verification failedssh-keygen -R [hostname or ip address]删除整个 known_hosts 文件 其它聊聊中间人攻击ssh 如何保证安全?加密流程漏洞在哪里如何避免中间人攻击 个人简介 前言 最近服务器…...
数据结构系统刷题
本文为系统刷leetcode的记录,会记录自己根据代码随想录刷过的leetcode,方便直接点开刷题,时常更新 时间复杂度简记为s 空间复杂度简记为k 数组 704 二分查找 一维二分查找 (1)[left, right] class Solution { publi…...
【RabbitMQ】延迟队列之死信交换机
🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《RabbitMQ实战》。🎯🎯 &am…...
2024交通运输工程与土木建筑工程国际会议(ICTECCE2024)
2024交通运输工程与土木建筑工程国际会议(ICTECCE2024) 会议简介 2024年国际交通工程和土木建筑工程会议(ICTECCE 2024)将在中国杭州举行。ICTECCE 2024致力于为交通工程和土木工程材料领域的学者、工程师和研究人员提供一个大型学术交流平台和双向交流…...
搜索引擎Elasticsearch了解
1.Lucene 是什么? 2.模块介绍 Lucene是什么: 一种高性能,可伸缩的信息搜索(IR)库 在2000年开源,最初由鼎鼎大名的Doug Cutting开发 是基于Java实现的高性能的开源项目 Lucene采用了基于倒排表的设计原理,可以非常高效地实现文本查找,在底层采用了分段的存储模式,使它在读…...
网站制作价格/怎么看关键词的搜索量
1. 本章小结 2. 常见问题和易混淆知识点 2.1 如何表示一个数值数据?计算机中的数值数据都是二进制数吗? 2.2 在高级语言编程中所定义的 unsigned/shortint/long/floatl/double型数据是怎么表示的?什么称为无符号整数的“溢出”? 2.3 如何判断一个浮点数是否是规格化数? 2.…...
廊坊市做网站/橙子建站怎么收费
NumberFormat 是全部数值格式的抽象基类。 该类提供了格式化和分析数值的接口。 NumberFormat 也提供了确定 哪个语言环境具有数值格式以及它们名字的方法。 package com.discursive.jccook.collections; import java.text.NumberFormat; public class Test { /** * param ar…...
外语网站建设目的/武汉seo网站排名优化公司
基本概念 光照影响整个场景的氛围,缺少光照还会缺乏三维的感觉。光照主要集中在光源的类型位置方向等参数,光照物体的材质(狭隘的指光照属性)和纹理,采用的光照模型。 OGL镜面高光颜色GL_SEPARATE_SPECULAR_COLOR在纹理处理Fragment 纹理映射…...
网站内容优化方法有哪些内容/seowhy
《战略管理》模拟题 单选题 1.IT行业变化快是一个典型的() A.长周期市场 B.标准周期市场 C.短周期市场 D.不能确定 2.当购买商们具有较强的讨价还价能力时从该行业购买的产品应该属于标准化的产品或是(). A.差异产品 B.无差别的产品 C.同质产品 D.类似产品 3.一家钢铁公司并…...
沈阳论坛建站模板/网站seo诊断分析报告
前2天看了老代的 这样的“牛”人最好别碰上 稍微有点儿感触,同样是客户可能差别都非常大。最近一个月我碰上了一个这样的客户他来自台湾,他在网上看到了我的作品,给我写了邮件要购买源码,结果我邮件没收到,他为了联系上…...
网站公司怎么做业务/最有效的宣传方式
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 6956 Solved: 2501[Submit][Status][Discuss]Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有…...