-
最新日志
最新评论
- tom 发表于《利用pthread_mutex对多进程上锁》
- tom 发表于《psi....qca-ossl》
- tom 发表于《psi....qca-ossl》
- tom 发表于《psi....qca-ossl》
- tom 发表于《psi....qca-ossl》
存档页
分类
功能
这废弃
Posted in 杂物箱
Leave a comment
利用pthread_mutex对多进程上锁
大三时候的系统结构实验,为了实现多进程的同步,由于变量都是进程的单独拷贝,所以超级傻的用了一个文件做标志,不同的进程对同一文件进行读写不同的数做锁。
其实POSIX_THREAD_PROCESS_SHARED支持就可以直接利用pthread_mutex_t进行进程间上锁
[code=c]
#include "unpheader.h"
#include <pthread.h>
#include <sys/mman.h>
static pthread_mutex_t *mptr;
void my_lock_init(void) //锁初始化,PTHREAD_PROCESS_SHARED属性
{
int fd;
pthread_mutexattr_t mattr;
fd=open("/dev/zero",O_RDWR,0);
mptr = mmap(0,sizeof(pthread_mutex_t),PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
close(fd);
pthread_mutexattr_init(&mattr);
pthread_mutexattr_setpshared(&mattr,PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mptr,&mattr);
}
int main(void)
{
pid_t pid;
my_lock_init();
if((pid = fork()) == 0) //child process
{
int i=0;
for(i=0;i<10;i++)
{
pthread_mutex_lock(mptr);
printf("child get mutex!\n");
sleep(1);
pthread_mutex_unlock(mptr);
sleep(1);
}
}
else //father process
{
int i=0;
for(i=0;i<10;i++)
{
pthread_mutex_lock(mptr);
printf("father get mutex!\n");
sleep(1);
pthread_mutex_unlock(mptr);
sleep(1);
}
}
return 0;
}
[/code]
unix socket取得网页html源文件
[code=c]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <alloca.h>
#define MAXLINE 1024
struct addrinfo *host_serv(const char *hostname,const char *service,int family,int sockettype)
{
int n;
struct addrinfo hints,*res;
bzero(&hints,sizeof(struct addrinfo));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = family;
hints.ai_socktype = sockettype;
if((n = getaddrinfo(hostname,service,&hints,&res))!=0)
return NULL;
return res;
}
int tcp_connect(const char* host,const char *serv)
{
int sockfd,n;
struct addrinfo *res,*ressave;
if((res=host_serv(host,serv,AF_UNSPEC,SOCK_STREAM)) == NULL)
{
printf("tcp_connect error for %s,%s:%s\n",host,serv,strerror(errno));
exit(-1);
}
ressave=res;
while(res != NULL)
{
sockfd = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
if(sockfd < 0)
continue;
if(connect(sockfd,res->ai_addr,res->ai_addrlen) == 0)
break;
close(sockfd);
res = res -> ai_next;
}
if(res == NULL)
{
printf("tcp_connect error for %s,%s",host,serv);
exit(-1);
}
freeaddrinfo(ressave);
return sockfd;
}
int read_html(const char *host,const char *file,int fd)
{
int sockfd,n;
char recvline[256];
char line[256];
sockfd = tcp_connect(host,"80");
int m=0;
if(file != NULL)
m=snprintf(line,sizeof(line),"GET /%s HTTP/1.0\r\n\r\n",file);
else //if there is no file specfied, the index.html will be got.
m=snprintf(line,sizeof(line),"GET / HTTP/1.0\r\n\r\n");
printf("%s\n",line);
write(sockfd,line,m);
while((n=read(sockfd,recvline,255)) >0)
{
recvline[n]=0;
write(fd,recvline,sizeof(recvline));
}
close(sockfd);
return 0;
}
void *printaddr_ip(struct addrinfo *test)
{
if(test == NULL)
{
printf("the input parameter addrinfo is NULL");
return;
}
while(test != NULL)
{
if( test -> ai_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in *) test-> ai_addr;
printf("canonname:%s IP:%s\n",test->ai_canonname,inet_ntoa( sin -> sin_addr));
test = test -> ai_next;
}
}
}
int getlength(const char* str)
{
const char *start = str;
int i=0;
while(*str != '\0')
{
i++;
str++;
}
str = start;
return i;
}
char *gethost(const char* hostfile,char *result,char *file)
{
if( result == NULL)
return NULL;
const char *start = hostfile;
const char *protocol[]={"http://","ftp://"}; //example protocol prefix
int i=0;
for(i=0;i< (sizeof(protocol)/sizeof(char *));i++)
{
if(strncmp(hostfile,protocol[i],sizeof(protocol[i])) == 0)
{
break;
}
}
if( i != (sizeof(protocol)/sizeof(char *)) ) //find procotol match
{
hostfile = hostfile + getlength(protocol[i]) ;
}
strcpy(result,hostfile);
char *end = strstr(result,"/");
if( end != NULL) //find file seperate
{
if( file != NULL)
strcpy(file,end+1);
*end = '\0';
}
else
file[0]='\0';
hostfile = start;
return result;
}
int main(int argc,char *argv[])
{
if(argc != 2 )
{
printf("usage: ./gethtml htmlpath\n");
return -1;
}
char result[MAXLINE],file[MAXLINE];
gethost(argv[1],result,file);
read_html(result,file,STDOUT_FILENO);
return 0;
}
[/code]
Posted in c/c++, unix
Leave a comment
查询主机的IP程序
参考unp第11章的 hostserv程序
[code=c]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
struct addrinfo *host_serv(const char *hostname,const char *service,int family,int sockettype)
{
int n;
struct addrinfo hints,*res;
bzero(&hints,sizeof(struct addrinfo));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = family;
hints.ai_socktype = sockettype;
if((n = getaddrinfo(hostname,service,&hints,&res))!=0)
return NULL;
return res;
}
int main(int argc,char *argv[])
{
if(argc != 2)
{
printf("usage: hostserv hostname\n");
return -1;
}
struct addrinfo *test;
test = host_serv(argv[1],NULL,AF_INET,SOCK_STREAM);
while(test != NULL)
{
if( test -> ai_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in *) test-> ai_addr;
printf("%s\n", inet_ntoa( sin -> sin_addr));
test = test -> ai_next;
}
}
return 0;
}
[/code]
Posted in c/c++, unix
Leave a comment
Unix域套接口及描述符传递
unix域协议是在单个主机上执行客户服务器通信方法,其实就是IPC的一种,但是程序的编写方式与TCP很类似,但比TCP套接口快出一倍的速度。
unix域套接口需要注意的是在UDP的unix套接口send之前需要显示的bind到一个pathname,这样服务器才有回答的路径。
unix域套接口传递描述符字采用sendmsg和recvmsg这两个函数的辅助数据msghdr进行传递,值得注意的是,在一方已经sendmsg的描述符字但是另外一端没有recvmsg之前(in flight),即使发送端关闭描述符字,接收方收到的描述符也是打开的。同时传递的是描述符字而不是一个字号,因此在接收进程中的描述符字号可能不同于发送进程。
socketpair是一个很有用的函数,很方便的创建了一个全双工的unix域套接口。
Posted in unix
Leave a comment
守护进程与inetd
守护进程是UNIX系统中非常重要的一种进程,简单来说就是在后台运行且不与任何终端交互的进程,此种程序的的登记消息方式采用syslog函数由syslogd进程来执行。
让一个进程成为守护进程的方法为:
fork生成子进程,_exit父进程,对子进程调用setsid使得子进程成为一个新会话的会话首进程,接着屏蔽SIGHUP信号(会话首进程结束时会话组中所有进程都会收到),再次fork,依旧结束父进程,这样最后的孙子进程就不是会话首进程,然后关闭所有的描述字,并将0,1,2三个描述字都打开到/dev/null,最后openlog促使消息登记(但如果不采用LOG_NDELAY选项则unix域套接口一直到首次调用syslog才打开)。
linux下提供的将进程转为守护进程的函数为daemon, 可参考man手册。
inetd是一种常用的守护进程,它可以将很多需要服务的程序由自己一个人处理,根据/etc/inetd.conf和/etc/service的配置,inetd创建FTP,TELNET等各种等待端口,当有客户连接时根据/etc/inetd.conf的参数创建子进程或者直接调用程序服务。
Posted in unix
Leave a comment
vim下的set ff设置
经常在工作中会碰到需要一些配置文件在不同的操作系统之间转移,最基本的就是win和unix下,有时候unix服务器我们没办法在上面进行编辑,就会在win下编辑后用工具传送过去,这样就引起了一个问题。
打开unix系统本身的一些文件,执行set ff?可以看到提示fileformat=unix,而我们传递过去的是fileformat=dos,这两种系统在换行符上处理稍有不同,如果一些配置文件依赖不同的行数是不同的配置,可能就会引起错误,尤其执行的时候可能不会报警就更加隐藏了问题。我们有时候用vim打开一些文档发现里面带^M字符其实就是这个问题。
解决问题就是set ff=unix 命令,很简单。
Posted in unix
Leave a comment
Unix下常见客户服务器范式比较
UNP第三十章。
a) 迭代型服务器(停-等)
已经不具备广泛实用性,仅在各个范式的比较中起基准作用
b) 并发性服务器(子进程)
主程序进行accept等待,为每一个客户fork一个子线程进行处理。
客户数目的限制是操作系统对运行服务器程序的用户ID能同时拥有子进程数的限制。
性能方面,由于现场fork的开销导致性能较为低下。
c) 预先派生子进程(进程池)
i. 子进程分别accept并不进行上锁保护:
预先派生进程池,当来客户连接时由子进程进行竞争,会引起”accept惊群”现象,即所有阻塞在accept的子进程都会被唤醒来竞争,但只有一个进程会返回并取得连接,其他子进程则继续阻塞等待,这种太多的子进程被唤醒会导致性能受损。
Btw:让子进程在accept上竞争的效果要远好于select上。
ii. 子进程分别accept进行上锁保护
此种方式让所有进程阻塞在锁的获取而不是accept套接口上,这样就会避免当连接到来时的accept的惊群作用。
上锁方式有两种,使用文件上锁,利用fcntl函数(SETLK和GETLK),另外一种采用线程上锁,需要将pthread_mutex_t用mmap映射到共享的内存区,然后设置pthread_mutexattr_t为PTHREAD_PROCESS_SHARED即可。后者比较方便并且不涉及文件操作,性能上会提升不少。
iii. 主线程等待并进行描述字分配。
这种技术导致父进程必须跟踪子进程的状态并采用unix域或者pipe进行描述符传送,UNP上采用socketpair()函数。如果为了使得各个子进程处理平衡,还得涉及算法平衡各个子进程的负载均衡,但是通常这样做没有必要,对于多个空闲子进程而言,谁处理连接并没有效率影响。
并且描述符的传递的效率要远低于采用锁的机制,除了父进程传递描述字,子进程处理完后还得传递状态。
d) 并发性服务器(线程)
一般线程操作会比进程更快一点,因此在支持线程的系统上采用线程是较好的方式。简单的现场生成新线程的范式也要快于进程池的版本(在Solaris和Digital Unix上,根据UNP的描述)。
e) 并发性服务器(线程池)
i. 每个线程各自accept
同样预先分配线程也会快于现场生成新线程,并且使用互斥锁将线程阻塞在锁上,此种方式的各个线程的负载均衡性是由线程调度算法导致,在互斥锁上轮询所有线程。
此种方式的速度是所有范式中最快的。
ii. 主线程accept并分配描述符字给子线程
实际上采用的是一个描述符字数组,主线程accept一个就往队列中添加一个,子线程取出一个就从队列中删除一个。对队列的添加和删除操作进行加锁保护。
速度慢于上面各线程分别accept的版本。
Posted in 杂物箱
Leave a comment
nokia机器一个小而烦恼的问题
就是短信的时间是接受的时间而不是发送的时间,本来问题不大,主要是关机,断点或者网络延迟时候收到短信却不知道对方是什么时候发的,苦恼啊....
貌似是所有的symbian s60v3rd都有的问题,但好像不确定,论坛上同一机型有些人有问题有些人没有,即使是同一版本的系统。
n78 欧水, 12.046版,谁有解决方案给来一个。
Posted in 杂物箱
Leave a comment