//必须指明主主键信息,才能明确到行,如果信息不能确定到具体的行的话,只能锁表,如id <> 3, //也会直接锁表. FOR UPDATE 仅适用于InnoDB,且必须在事务区块(BEGIN/COMMIT)中才能生效。 select * from tableA where id=*** FOR UPDATE
top//每隔5秒显式所有进程的资源占用情况 top -d 2//每隔2秒显式所有进程的资源占用情况 top -c //每隔5秒显式进程的资源占用情况,并显示进程的命令行参数(默认只有进程名) top -p12345 -p6789//每隔5秒显示pid是12345和pid是6789的两个进程的资源占用情况 top -d 2 -c -p123456//每隔2秒显示pid是12345的进程的资源使用情况,并显式该进程启动的命令行参数
//关闭连接 void TcpConnection::forceCloseInLoop() { loop_->assertInLoopThread(); if (state_ == kConnected || state_ == kDisconnecting) { // as if we received 0 byte in handleRead(); handleClose(); } }
如果此时port A 等于 port B, 那么此时实际上是没有服务器在port B 上监听的,不然的话,client不会分配到port B。在这种情况下,client发送的SYN包会来到端口B上,此时由于client已经打开了端口B,系统会以为端口B上有服务器在监听,那么就直接接收SYN包,并发给client。这种情况其实就是client和server同时发起连接,client此时的状态为SYN_RECEIVE,按照TCP的三次握手,client会跟自己建立起了连接。此时就出现了自连接。
void EventLoop::quit() { quit_ = true; // There is a chance that loop() just executes while(!quit_) and exits, // then EventLoop destructs, then we are accessing an invalid object. // Can be fixed using mutex_ in both places. if (!isInLoopThread()) { wakeup(); } }
(1) The gettid() system call first appeared on Linux in kernel 2.4.11. (2) gettid() returns the thread ID of the current process. This is equal to the process ID (as returned by getpid(2)), unless the process is part of a thread group (created by specifying the CLONE_THREAD flag to the clone(2) system call). All processes in the same thread group have the same PID, but each one has a unique TID. (3) gettid() is Linux specific and should not be used in programs that are intended to be portable. (如果考虑移植性,不应该使用此接口)
1 2 3 4 5
#include<sys/syscall.h> #define gettidv1() syscall(__NR_gettid) #define gettidv2() syscall(SYS_gettid) printf("The ID of this thread is: %ld\n", (longint)gettidv1());// 最新的方式 printf("The ID of this thread is: %ld\n", (longint)gettidv2());// 传统方式
voidbuildTree(){ queue <int> q; int p0 = 1; while (ath[p0][0]) p0 = ath[p0][0]; d[p0] = 1; q. push(p0); while (!q. empty()) { int p = q. front(); q. pop(); for (int i = 1; i < maxl; ++ i) ath[p][i] = ath[ath[p][i - 1]][i - 1]; for (vector <int> :: iterator i = e[p]. begin(); i != e[p]. end(); ++ i) { q. push(*i); d[*i] = d[p] + 1; } } }
intLCA(int p, int q){ if (d[p] < d[q]) swap(p, q); for (int i = maxl - 1; i >= 0; -- i) if (d[ath[p][i]] >= d[q]) p = ath[p][i]; if (p == q) return p; for (int i = maxl - 1; i >= 0; -- i) if (ath[p][i] ^ ath[q][i]) p = ath[p][i], q = ath[q][i]; return ath[p][0]; }
intmain(){ cin. sync_with_stdio(0); cin >> n; tn = 0; while (n --) { string a, b; cin >> a >> b; int na = getNum(a), nb = getNum(b); ath[nb][0] = na; e[na]. push_back(nb); } buildTree(); cin >> m; while (m --) { string a, b; cin >> a >> b; int na = getNum(a), nb = getNum(b); cout << name[LCA(na, nb)] << endl; } }
A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:
In the figure, each node is labeled with an integer from {1, 2,…,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is.
For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest common ancestor of y and z is y.
Write a program that finds the nearest common ancestor of two distinct nodes in a tree.
Input
The input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case starts with a line containing an integer N , the number of nodes in a tree, 2<=N<=10,000. The nodes are labeled with integers 1, 2,…, N. Each of the next N -1 lines contains a pair of integers that represent an edge –the first integer is the parent node of the second integer. Note that a tree with N nodes has exactly N - 1 edges. The last line of each test case contains two distinct integers whose nearest common ancestor is to be computed. Output
Print exactly one line for each test case. The line should contain the integer that is the nearest common ancestor.
After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, some materials needed can only be produced in certain places. So we need to transport these materials from city to city. For most of roads had been totally destroyed during the war, there might be no path between two cities, no circle exists as well. Now, your task comes. After giving you the condition of the roads, we want to know if there exists a path between any two cities. If the answer is yes, output the shortest path between them.
Input
Input consists of multiple problem instances.For each instance, first line contains three integers n, m and c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000. n represents the number of cities numbered from 1 to n. Following m lines, each line has three integers i, j and k, represent a road between city i and city j, with length k. Last c lines, two integers i, j each line, indicates a query of city i and city j.
Output
For each problem instance, one line for each query. If no path between two cities, output “Not connected”, otherwise output the length of the shortest path between them.
#define lchild rt << 1, l, m #define rchild rt << 1 | 1, m + 1, r voidupdate(int p, int delta, int rt = 1, int l = 1, int r = N){ if (l == r) { tree[rt] += delta; return; } int m = (l + r) >> 1; if (p <= m) update(p, delta, lchild); else update(p, delta, rchild); push_up(rt); }
成段更新,需要用到lazy来提高效率,下面代码是区间和的情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#define lchild rt << 1, l, m #define rchild rt << 1 | 1, m + 1, r voidupdate(int L, int R, int delta, int rt = 1, int l = 1, int r = N){ if (L <= l && r <= R) { tree[rt] += delta * (r - l + 1); lazy[rt] += delta; return; } if (lazy[rt]) push_down(rt, r - l + 1); int m = (l + r) >> 1; if (L <= m) update(L, R, delta, lchild); if (R > m) update(L, R, delta, rchild); push_up(rt); }
query
查询也是要根据具体功能来实现,下面是查询区间和的代码
1 2 3 4 5 6 7 8 9 10
#define lchild rt << 1, l, m #define rchild rt << 1 | 1, m + 1, r int query(int L, int R, int rt = 1, int l = 1, int r = N) { if (L <= l && r <= R) return tree[rt]; if (lazy[rt]) push_down(rt, r - l + 1); int m = (l + r) >> 1, ret = 0; if (L <= m) ret += query(L, R, lchild); if (R > m) ret += query(L, R, rchild); returnret; }
The inversion number of a given number sequence a1, a2, …, an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.
For a given sequence of numbers a1, a2, …, an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:
a1, a2, …, an-1, an (where m = 0 - the initial seqence) a2, a3, …, an, a1 (where m = 1) a3, a4, …, an, a1, a2 (where m = 2) … an, a1, a2, …, an-1 (where m = n-1)
You are asked to write a program to find the minimum inversion number out of the above sequences.
Input
The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1.
Output
For each case, output the minimum inversion number on a single line.
#define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 constint maxn = 5555; int sum[maxn<<2]; voidPushUP(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } voidbuild(int l,int r,int rt){ sum[rt] = 0; if (l == r) return ; int m = (l + r) >> 1; build(lson); build(rson); } voidupdate(int p,int l,int r,int rt){ if (l == r) { sum[rt] ++; return ; } int m = (l + r) >> 1; if (p <= m) update(p , lson); else update(p , rson); PushUP(rt); } intquery(int L,int R,int l,int r,int rt){ if (L <= l && r <= R) { return sum[rt]; } int m = (l + r) >> 1; int ret = 0; if (L <= m) ret += query(L , R , lson); if (R > m) ret += query(L , R , rson); return ret; } int x[maxn]; intmain(){ int n; while (~scanf("%d",&n)) { build(0 , n - 1 , 1); int sum = 0; for (int i = 0 ; i < n ; i ++) { scanf("%d",&x[i]); sum += query(x[i] , n - 1 , 0 , n - 1 , 1); update(x[i] , 0 , n - 1 , 1); } int ret = sum; for (int i = 0 ; i < n ; i ++) { sum += n - x[i] - x[i] - 1; ret = min(ret , sum); } printf("%d\n",ret); } return0; }
At the entrance to the university, there is a huge rectangular billboard of size h*w (h is its height and w is its width). The board is the place where all possible announcements are posted: nearest programming competitions, changes in the dining room menu, and other important information.
On September 1, the billboard was empty. One by one, the announcements started being put on the billboard.
Each announcement is a stripe of paper of unit height. More specifically, the i-th announcement is a rectangle of size 1 * wi.
When someone puts a new announcement on the billboard, she would always choose the topmost possible position for the announcement. Among all possible topmost positions she would always choose the leftmost one.
If there is no valid location for a new announcement, it is not put on the billboard (that’s why some programming contests have no participants from this university).
Given the sizes of the billboard and the announcements, your task is to find the numbers of rows in which the announcements are placed.
Input
There are multiple cases (no more than 40 cases).
The first line of the input file contains three integer numbers, h, w, and n (1 <= h,w <= 10^9; 1 <= n <= 200,000) - the dimensions of the billboard and the number of announcements.
Each of the next n lines contains an integer number wi (1 <= wi <= 10^9) - the width of i-th announcement.
Output
For each announcement (in the order they are given in the input file) output one number - the number of the row in which this announcement is placed. Rows are numbered from 1 to h, starting with the top row. If an announcement can’t be put on the billboard, output “-1” for this announcement.
In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.
Now Pudge wants to do some operations on the hook.
Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks. The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:
For each cupreous stick, the value is 1. For each silver stick, the value is 2. For each golden stick, the value is 3.
Pudge wants to know the total value of the hook after performing the operations. You may consider the original hook is made up of cupreous sticks.
Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases. For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations. Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.
Output
For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.
#define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 constint maxn = 111111; int h , w , n; int col[maxn<<2]; int sum[maxn<<2]; voidPushUp(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } voidPushDown(int rt,int m){ if (col[rt]) { col[rt<<1] = col[rt<<1|1] = col[rt]; sum[rt<<1] = (m - (m >> 1)) * col[rt]; sum[rt<<1|1] = (m >> 1) * col[rt]; col[rt] = 0; } } voidbuild(int l,int r,int rt){ col[rt] = 0; sum[rt] = 1; if (l == r) return ; int m = (l + r) >> 1; build(lson); build(rson); PushUp(rt); } voidupdate(int L,int R,int c,int l,int r,int rt){ if (L <= l && r <= R) { col[rt] = c; sum[rt] = c * (r - l + 1); return ; } PushDown(rt , r - l + 1); int m = (l + r) >> 1; if (L <= m) update(L , R , c , lson); if (R > m) update(L , R , c , rson); PushUp(rt); } intmain(){ int T , n , m; scanf("%d",&T); for (int cas = 1 ; cas <= T ; cas ++) { scanf("%d%d",&n,&m); build(1 , n , 1); while (m --) { int a , b , c; scanf("%d%d%d",&a,&b,&c); update(a , b , c , 1 , n , 1); } printf("Case %d: The total value of the hook is %d.\n",cas , sum[1]); } return0; }
You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000. The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000. Each of the next Q lines represents an operation. “C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000. “Q a b” means querying the sum of Aa, Aa+1, … , Ab.
Output
You need to answer all Q commands in order. One answer in a line.
//加锁的实现函数,成功返回null,不成功返回锁的存活时间,-1表示锁永不超时 private Long tryLockInner() { //保存锁的状态: 客户端UUID+线程ID来唯一标识某一JVM实例的某一线程 final LockValue currentLock = new LockValue(id, Thread.currentThread().getId());
JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限 制;系统的可用物理内存限制。32位系统下,一般限制在1.5G~2G;64为操作系统对内存无限制。在 Windows Server 2003 系统,3.5G物理内存,JDK5.0下测试,最大可设置为1478m。 典型设置:
Class cls = Class.forName("chb.test.reflect.Student"); Method m = cls.getDeclaredMethod("hi",newClass[]{int.class,String.class}); m.invoke(cls.newInstance(),20,"chb");
//static方法调用时,不必得到对象 Class cls = Class.forName("chb.test.reflect.Student"); Method staticMethod = cls.getDeclaredMethod("hi",int.class,String.class); staticMethod.invoke(cls,20,"chb");//这里不需要newInstance
//运行错误输出 java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at classloader.ClassIdentity.testClassIdentity(ClassIdentity.java:26) at classloader.ClassIdentity.main(ClassIdentity.java:9) Caused by: java.lang.ClassCastException: com.example.Sample cannot be cast to com.example.Sample at com.example.Sample.setSample(Sample.java:7) ... 6 more
但是同步一个方法可能造成程序执行效率降低100倍,而且其实在getInstance函数中,并不是整一个方法都属于资源竞争的范围,只有uniqueInstance = new Singleton()语句才是,而且只有在单例对象第一次初始化的时候才会执行该语句,其余的都不会进入到该语句中,所以直接对整一个方法进行同步有点浪费。 可以双重检查加锁,在getInstance函数中减少同步
public class PizzaStore{ public Pizza orderPizza(Stringtype){ Pizza p; if("aa".equals(type)) p = new AAPizaa(); //AAPizza为Pizaa的子类 if("bb".equals(type)) p = BBPizaa(); //BBPizza为Pizaa的子类 if... ... ... return p;
//实例化的工作被抽离出来 public class SimplePizzaFactory{ public SimplePizzaFactory(){}; public Pizza createPizza(Stringtype){ if("aa".equals(type)) reutrn new AAPizza(); //AAPizza为Pizza的子类 if("bb".equals(type)) return BBPizza(); //BBPizza为Pizza的子类 if... ... } } public class PizzaStore{ SimplePizzaFactory spf; public PizzaStore(SimplePizzaFactory spf){ this.spf = spf; } public Pizza orderPizza(Stringtype){ Pizza p; p = spf.createPizza(type); ... ... return p;
public abstractclassPizzaStore(){ abstractPizza createPizza(Stringtype);//工厂方法,具体pizza类的实例化由派生类来实现 public Pizza orderPizza(Stringtype){ Pizza p; p = createPizza(type);
} }
//具体的对象实例化由派生类决定 public classAAPizzaStore() extendsPizzaStore{ Pizza createPizza(Stringtype){ System.out.println("I'm AAPizzaStore"); if("aa".equals(type)) reutrn newAA1Pizza(); //AA1Pizza为Pizza的子类 if("bb".equals(type)) returnAA2Pizza(); //AA2Pizza为Pizza的子类 if ... ... }
}
public classBBPizzaStore() extendsPizzaStore{ Pizza createPizza(Stringtype){ System.out.println("I'm BBPizzaStore"); if("aa".equals(type)) reutrn newBB1Pizza(); //BB1Pizza为Pizza的子类 if("bb".equals(type)) returnBB2Pizza(); //BB2Pizza为Pizza的子类 if ... ... }
auto i = 42; auto a = 3.14; auto p = new Ptr(); auto i=0,&r=i; auto a=r;//a为int,因为r是i的别名,i为int。 vector<int> v; auto b = v.begin(); std::map<std::string, std::vector<int>> map; for(auto it = begin(map); it != end(map); ++it) {};
decltype(f()) sum=x; //sum的类型就是f返回值的类型, 但是这里不执行函数f() auto x= 12; auto y = 13; typedefdecltype(x*y) Type; decltype(x*y) xy; //xy的类型为int //decltype声明函数指针的时,关键是要记住decltype返回的是一个函数的类型的,因此要加上*声明符才能构成完整的函数指针的类型 intf(int a, int b){return a+b;}; decltype(f)* k = f; //直接decltype(f) k = f 是不可以的 k(1, 2);
int k=9; decltype(*p) c=k; //c为int&,必须初始化 decltype((i)) d = k; //d为int&,必须初始化 decltype(++i) e = k //e为int&, 必须初始化 decltype(i++) f; //f 为int类型 tecltype(f=k) g //g为int&类型,必须初始化
onst int ci=i,&cr=i; auto a=ci; //a为int(忽略顶层const) auto b=cr; //b为int(忽略顶层const,cr是引用) auto c=&i; //c为int * auto d=&ci; //d是pointer to const int(&ci为底层const) //要声明顶层const,前面要加上const关键字;要声明引用要加上&标识符 constauto f=ci; //ci的推演类型是int,f是const int auto &g=ci;// g是一个绑定到ci的引用
对于decltype,其对const和应用的处理如下
1 2 3 4 5 6
constint ci=0; decltype(ci) x=0; //x的类型是const int int i=42,*p=&i,&r=i; decltype(r+0) b; //b为int constint &cj=ci; decltype(cj) y=x; //y的类型是const int&,y绑定到x上
template<class T> class A { public: staticconstexpr T min()throw(){ return T(); } staticconstexpr T max()throw(){ return T(); } staticconstexpr T lowest()throw(){ return T(); } ...
而在C++11中,则使用noexcept来替换throw()。
1 2 3 4 5 6
template<class T> class A { public: staticconstexpr T min()noexcept{ return T(); } staticconstexpr T max()noexcept{ return T(); } staticconstexpr T lowest()noexcept{ return T(); } ...
struct Point { int x,y; constexpr Point(int xx, int yy) : x(xx), y(yy) { } }; constexpr Point origo(0,0); constexpr int z = origo.x; constexpr Point a[] = {Point(0,0), Point(1,1), Point(2,2) }; constexpr int x = a[1].x; // x becomes 1
template <typename T1, typename T2> auto add(T1 t1, T2 t2) -> decltype(t1 + t2) { static_assert(std::is_integral<T1>::value, "Type T1 must be integral"); static_assert(std::is_integral<T2>::value, "Type T2 must be integral");
return t1 + t2; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14
error C2338: Type T2 must be integral see reference tofunction template instantiation 'T2 add<int,double>(T1,T2)' being compiled with [ T2=double, T1=int ] error C2338: Type T1 must be integral see reference tofunction template instantiation 'T1 add<const char*,int>(T1,T2)' being compiled with [ T1=constchar *, T2=int ]
/*系统中的每个信号灯集对应一个sem_array 结构 */ struct sem_array { struct kern_ipc_perm sem_perm; /* permissions .. see ipc.h */ time_t sem_otime; /* last semop time */ time_t sem_ctime; /* last change time */ struct sem *sem_base; /* ptr to first semaphore in array */ struct sem_queue *sem_pending; /* pending operations to be processed */ struct sem_queue **sem_pending_last; /* last pending operation */ struct sem_undo *undo; /* undo requests on this array */ unsigned long sem_nsems; /* no. of semaphores in array */ };
其中,sem_queue结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* 系统中每个因为信号灯而睡眠的进程,都对应一个sem_queue结构*/ struct sem_queue { struct sem_queue * next; /* next entry in the queue */ struct sem_queue ** prev; /* previous entry in the queue, *(q->prev) == q */ struct task_struct* sleeper; /* this process */ struct sem_undo * undo; /* undo structure */ int pid; /* process id of requesting process */ int status; /* completion status of operation */ struct sem_array * sma; /* semaphore array for operations */ int id; /* internal sem id */ struct sembuf * sops; /* array of pending operations */ int nsops; /* number of operations */ int alter; /* operation will alter semaphore */ };
union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ unsignedshort *array; /* array for GETALL & SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO *///test!! void *__pad; }; struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem; };
#include<linux/sem.h> #include<stdio.h> #include<errno.h> #define SEM_PATH "/unix/my_sem" #define max_tries 3 int semid; main() { int flag1,flag2,key,i,init_ok,tmperrno; struct semid_ds sem_info; struct seminfo sem_info2; union semun arg; //union semun: 请参考附录2 struct sembuf askfor_res, free_res; flag1=IPC_CREAT|IPC_EXCL|00666; flag2=IPC_CREAT|00666; key=ftok(SEM_PATH,'a'); //error handling for ftok here; init_ok=0; semid=semget(key,1,flag1); //create a semaphore set that only includes one semphore. if(semid<0) { tmperrno=errno; perror("semget"); if(tmperrno==EEXIST) //errno is undefined after a successful library call( including perror call) //so it is saved in tmperrno. { semid=semget(key,1,flag2); //flag2 只包含了IPC_CREAT标志, 参数nsems(这里为1)必须与原来的信号灯数目一致 arg.buf=&sem_info; for(i=0; i<max_tries; i++) { if(semctl(semid, 0, IPC_STAT, arg)==-1) { perror("semctl error"); i=max_tries;} else { if(arg.buf->sem_otime!=0){ i=max_tries; init_ok=1;} else sleep(1); } } if(!init_ok) // do some initializing, here we assume that the first process that creates the sem // will finish initialize the sem and run semop in max_tries*1 seconds. else it will // not run semop any more. { arg.val=1; if(semctl(semid,0,SETVAL,arg)==-1) perror("semctl setval error"); } } else {perror("semget error, process exit"); exit(); } } else//semid>=0; do some initializing { arg.val=1; if(semctl(semid,0,SETVAL,arg)==-1) perror("semctl setval error"); } //get some information about the semaphore and the limit of semaphore in redhat8.0 arg.buf=&sem_info; if(semctl(semid, 0, IPC_STAT, arg)==-1) perror("semctl IPC STAT"); printf("owner's uid is %d\n", arg.buf->sem_perm.uid); printf("owner's gid is %d\n", arg.buf->sem_perm.gid); printf("creater's uid is %d\n", arg.buf->sem_perm.cuid); printf("creater's gid is %d\n", arg.buf->sem_perm.cgid); arg.__buf=&sem_info2; if(semctl(semid,0,IPC_INFO,arg)==-1) perror("semctl IPC_INFO"); printf("the number of entries in semaphore map is %d \n", arg.__buf->semmap); printf("max number of semaphore identifiers is %d \n", arg.__buf->semmni); printf("mas number of semaphores in system is %d \n", arg.__buf->semmns); printf("the number of undo structures system wide is %d \n", arg.__buf->semmnu); printf("max number of semaphores per semid is %d \n", arg.__buf->semmsl); printf("max number of ops per semop call is %d \n", arg.__buf->semopm); printf("max number of undo entries per process is %d \n", arg.__buf->semume); printf("the sizeof of struct sem_undo is %d \n", arg.__buf->semusz); printf("the maximum semaphore value is %d \n", arg.__buf->semvmx);
//now ask for available resource: askfor_res.sem_num=0; askfor_res.sem_op=-1; askfor_res.sem_flg=SEM_UNDO;
if(semop(semid,&askfor_res,1)==-1)//ask for resource perror("semop error");
sleep(3); //do some handling on the sharing resource here, just sleep on it 3 seconds printf("now free the resource\n");
//now free resource free_res.sem_num=0; free_res.sem_op=1; free_res.sem_flg=SEM_UNDO; if(semop(semid,&free_res,1)==-1)//free the resource. if(errno==EIDRM) printf("the semaphore set was removed\n"); //you can comment out the codes below to compile a different version: if(semctl(semid, 0, IPC_RMID)==-1) perror("semctl IPC_RMID"); elseprintf("remove sem ok\n"); }
owner's uid is 0 owner's gid is0 creater's uid is 0 creater's gid is0 the number of entries in semaphore map is32000 max number of semaphore identifiers is128 mas number of semaphores in system is32000 the number of undo structures system wide is32000 max number of semaphores per semid is250 max number of ops per semop call is32 max number of undo entries per process is32 the sizeof of struct sem_undo is20 the maximum semaphore value is32767 now free the resource remove sem ok
int ipc(unsigned intcall, intfirst, int second, int third, void * ptr, long fifth); 第一个参数指明对IPC对象的操作方式,对消息队列而言共有四种操作:MSGSND、MSGRCV、MSGGET以及MSGCTL,分别代表向消息队列发送消息、从消息队列读取消息、打开或创建消息队列、控制消息队列;first参数代表唯一的IPC对象;下面将介绍四种操作.
struct msg_queue { struct kern_ipc_perm q_perm; time_t q_stime; /* last msgsnd time */ time_t q_rtime; /* last msgrcv time */ time_t q_ctime; /* last change time */ unsignedlong q_cbytes; /* current number of bytes on queue */ unsignedlong q_qnum; /* number of messages in queue */ unsignedlong q_qbytes; /* max number of bytes on queue */ pid_t q_lspid; /* pid of last msgsnd */ pid_t q_lrpid; /* last receive pid */ struct list_head q_messages; struct list_head q_receivers; struct list_head q_senders; };
结构msqid_ds用来设置或返回消息队列的信息,存在于用户空间;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
struct msqid_ds { struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue,unused */ struct msg *msg_last; /* last message in queue,unused */ __kernel_time_t msg_stime; /* last msgsnd time */ __kernel_time_t msg_rtime; /* last msgrcv time */ __kernel_time_t msg_ctime; /* last change time */ unsignedlong msg_lcbytes; /* Reuse junk fields for 32 bit */ unsignedlong msg_lqbytes; /* ditto */ unsignedshort msg_cbytes; /* current number of bytes on queue */ unsignedshort msg_qnum; /* number of messages in queue */ unsignedshort msg_qbytes; /* max number of bytes on queue */ __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ };
current number of bytes on queue is 0 number of messages in queue is 0 max number of bytes on queue is 16384 pid of last msgsnd is 0 pid of last msgrcv is 0 last msgsnd time is Thu Jan 1 08:00:00 1970 last msgrcv time is Thu Jan 1 08:00:00 1970 last changetimeis Sun Dec2918:28:202002 msg uid is0 msg gid is0 //上面刚刚创建一个新消息队列时的输出 currentnumberofbyteson queue is1 numberof messages in queue is1 maxnumberofbyteson queue is16384 pid oflast msgsnd is2510 pid oflast msgrcv is0 last msgsnd timeis Sun Dec2918:28:212002 last msgrcv timeis Thu Jan 108:00:001970 lastchangetimeis Sun Dec2918:28:202002 msg uid is0 msg gid is0 readfrom msg queue 1bytes //实际读出的字节数 currentnumberofbyteson queue is0 numberof messages in queue is0 maxnumberofbyteson queue is16384 //每个消息队列最大容量(字节数) pid oflast msgsnd is2510 pid oflast msgrcv is2510 last msgsnd timeis Sun Dec2918:28:212002 last msgrcv timeis Sun Dec2918:28:222002 lastchangetimeis Sun Dec2918:28:202002 msg uid is0 msg gid is0 currentnumberofbyteson queue is0 numberof messages in queue is0 maxnumberofbyteson queue is16388 //可看出超级用户可修改消息队列最大容量 pid oflast msgsnd is2510 pid oflast msgrcv is2510 //对操作消息队列进程的跟踪 last msgsnd timeis Sun Dec2918:28:212002 last msgrcv timeis Sun Dec2918:28:222002 lastchangetimeis Sun Dec2918:28:232002 //msgctl()调用对msg_ctime有影响 msg uid is8 msg gid is8
/*-------------map_normalfile1.c-----------*/ #include<sys/mman.h> #include<sys/types.h> #include<fcntl.h> #include<unistd.h> typedefstruct{ char name[4]; int age; }people; main(int argc, char** argv) // map a normal file as shared mem: { int fd,i; people *p_map; char temp;
在map_normalfile1输出initialize over 之后,输出umap ok之前,在另一个终端上运行map_normalfile2 /tmp/test_shm,将会产生如下输出(为了节省空间,输出结果为稍作整理后的结果):
1 2
name: b age 20; name: c age 21; name: d age 22; name: e age 23; name: f age 24; name: g age 25; name: h age 26; name: I age 27; name: j age 28; name: k age 29;
name: b age 20; name: c age 21; name: d age 22; name: e age 23; name: f age 24; name: age 0; name: age 0; name: age 0; name: age 0; name: age 0;
从程序的运行结果中可以得出的结论
1、最终被映射文件的内容的长度不会超过文件本身的初始大小,即映射不能改变文件的大小;
2、可以用于进程通信的有效地址空间大小大体上受限于被映射文件的大小,但不完全受限于文件大小。打开文件被截短为5个people结构大小,而在map_normalfile1中初始化了10个people数据结构,在恰当时候(map_normalfile1输出initialize over 之后,输出umap ok之前)调用map_normalfile2会发现map_normalfile2将输出全部10个people结构的值,后面将给出详细讨论。 注:在linux中,内存的保护是以页为基本单位的,即使被映射文件只有一个字节大小,内核也会为映射分配一个页面大小的内存。当被映射文件小于一个页面大小时,进程可以对从mmap()返回地址开始的一个页面大小进行访问,而不会出错;但是,如果对一个页面以外的地址空间进行访问,则导致错误发生,后面将进一步描述。因此,可用于进程间通信的有效地址空间大小不会超过文件大小及一个页面大小的和。
name: b age 20; name: c age 21; name: d age 22; name: e age 23; name: f age 24; name: g age 25; name: h age 26; name: I age 27; name: j age 28; name: k age 29;
当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。注:(PIPE_BUF在include/linux/limits.h中定义,不同的内核版本可能会有所不同。Posix.1要求PIPE_BUF至少为512字节,red hat 7.2中为4096)。
if((pid=fork())==0) { printf("\n"); close(pipe_fd[1]); sleep(3);//确保父进程关闭写端 r_num=read(pipe_fd[0],r_buf,100); printf( "read num is %d the data read from the pipe is %d\n",r_num,atoi(r_buf));
close(pipe_fd[0]); exit(); } else if(pid>0) { close(pipe_fd[0]);//read strcpy(w_buf,"111"); if(write(pipe_fd[1],w_buf,4)!=-1) printf("parent write over\n"); close(pipe_fd[1]);//write printf("parent close fd[1] over\n"); sleep(10); } } /************************************************** * 程序输出结果: * parent write over * parent close fd[1] over * read num is 4 the data read from the pipe is 111 * 附加结论: * 管道写端关闭后,写入的数据将一直存在,直到读出为止. ****************************************************/
exit(); } elseif(pid>0) { close(pipe_fd[0]);//write memset(r_buf,0,sizeof(r_buf)); if((writenum=write(pipe_fd[1],w_buf,1024))==-1) printf("write to pipe error\n"); else printf("the bytes write to pipe is %d \n", writenum); writenum=write(pipe_fd[1],w_buf,4096); close(pipe_fd[1]); } } 输出结果: the bytes write to pipe 1000 the bytes write to pipe 1000//注意,此行输出说明了写入的非原子性 the bytes write to pipe 1000 the bytes write to pipe 1000 the bytes write to pipe 1000 the bytes write to pipe 120//注意,此行输出说明了写入的非原子性 the bytes write to pipe 0 the bytes write to pipe 0 ......
管道应用的一个重大限制是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named pipe或FIFO)提出后,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。
} inthandle_client(char* arg) { int ret; ret=w_open(arg); switch(ret) { case0: { printf("open %s error\n",arg); printf("no process has the fifo open for reading\n"); return -1; } case -1: { printf("something wrong with open the fifo except for ENXIO"); return -1; } case1: { printf("open server ok\n"); return1; } default: { printf("w_no_r return ----\n"); return0; } } unlink(FIFO_SERVER); } intw_open(char*arg) //0 open error for no reading //-1 open error for other reasons //1 open ok { if(open(arg,O_WRONLY|O_NONBLOCK,0)==-1) { if(errno==ENXIO) { return0; } else return -1; } return1;
/* Send to clients listening for that channel */ // 取出包含所有订阅频道 channel 的客户端的链表 // 并将消息发送给它们 de = dictFind(server.pubsub_channels,channel); if (de) { list *list = dictGetVal(de); listNode *ln; listIter li;
ICMP 经常被认为是 IP 层的一个组成部分,它传递差错报文以及其他需要注意的信息。ICMP 报文通常被 IP 层或更高层协议(TCP 或 UDP)使用。ICMP 报文是在 IP 数据报内部传输的。IP 协议是不可靠协议,不能保证 IP 数据报能够成功的到达目的主机,无法进行差错控制,而 ICMP 协议能够协助 IP 协议完成这些功能。下面是 ICMP 报文的数据结构:
类型:一个 8 位类型字段,表示 ICMP 数据包类型;
代码:一个 8 位代码域,表示指定类型中的一个功能,如果一个类型中只有一种功能,代码域置为 0;
检验和:数据包中 ICMP 部分上的一个 16 位检验和;
以下针对 ICMP 差错报文的类型进行分析:
1、ICMP 目标不可达消息:IP 路由器无法将 IP 数据报发送给目的地址时,会给发送端主机返回一个目标不可达 ICMP 消息,并在这个消息中显示不可达的具体原因。
port restricted cone类型在restricted cone类型的基础上增加了port的限制,必须又内网的机器访问外网机器的某个端口,该外网机器的对应端口发出的数据包才可以通过NAT。NAT维持的映射关系如下: {对端外网ip:对端外网port:内网ip:内网port}—->{公网ip:公网port},同一个机器的特定端口才可以通过该映射。
classB { UINT valueB; //error C2146: syntax error : missing ';' before identifier 'valueB' //error C4430: missing type specifier - int assumed. Note: C++ does not support default-int };
extern 用来声明一个外部变量或是函数,表示该变量已经在其他的地方定义了,这里只是做一个引用而已,不会产生新的变量。对于extern修饰的变量,编译器会在所在的文件先看看有没有对该变量的定义,有的话,直接应用,没有的话再到其他的文件里面进行查找。由于变量已经在其他的地方定义了,所以extern int a = 10;这种写法是不对的,会造成重定义错误!
寄存器变量,请求编译器将这个变量保存在CPU的寄存器中,从而加快程序的运行。系统的寄存器是有限制的,声明变量时如:register int i.这种存储类型可以用于频繁使用的变量。实际上现在一般的编译器都忽略auto和register申明,现在的编译器自己能够区分最好将那些变量放置在寄存器中,那些放置在堆栈中;甚至于将一些变量有时存放在堆栈,有时存放在寄存器中。