project-te

总结这一段时间做te项目时遇到的小问题。

一、alarm(), signal()函数

alarm()函数
头文件: #include 
原型:unsigned int alarm(unsigned int seconds);
功能:经过seconds秒后,向目前的进程发送SIGALARM信号

返回值:若调用多个alarm函数,则第二个alarm将取代第一个,并返回第一个alarm的生于时间。
详见:https://typecodes.com/linux/linuxalarmknockfunc.html

signal()函数
头文件:#include 
原型:sighandler_t signal(int signum, sighandler_t handler);
功能:截取signum信号,截取成功后执行handler指向的函数

handler是一个函数指针,指向一个void sig_handle(int signo)函数,用户在sig_handle函数中定义所需动作。

handler也可以是 SIG_IGN和SIG_DFL。
SIG_IGN表示屏蔽该信号;
SIG_DFL表示恢复该信号的默认设置。

另:handler函数应该为静态函数。

二、c++静态成员函数

c++中,类的静态成员属于类,而不属于某个对象,因此可以通过静态成员在同一类的对象中共享数据。

静态成员函数的声明(.h文件):
class example
{
  public:
    static void handle(int signo);
};

静态成员函数的实现(.cpp文件):
void examp::handle(int signo)//不用加static
{
......
}

静态成员函数的引用:
1.像其他成员函数一样
对象::handler(..);
2.直接通过类名引用
example::handler(...);

三、fcntl()函数

头文件:#include 
       #include 
       #include 
原型:int fcntl(int fd, int cmd, ...);
功能:改变文件描述符的属性

如:

//将服务器端口设为非阻塞
fcntl(server_sockfd, F_SETFL, fcntl(server_sockfd, F_GETFL, 0)|O_NONBLOCK);

详见:https://blog.csdn.net/bailyzheng/article/details/7463775

三、linux线程编程

同一个进程中的所有线程共享资源。

线程的创建和结束

1.pthread_create()

int pthread_create(
  pthread_t *thread, 
  pthread_attr_t *attr,  
  void* (*static_routine)(void *),
  void *arg);

thread:线程的标识
attr:线程的属性,设为NULL表示默认属性
start_routine:线程中运行的单元,用户自己编写
arg:线程函数运行时传入的参数

线程创建成功返回0,失败返回非0值。
在c++里,类中需要调用pthread_creat函数时,static_routine应为是静态函数的指针,可采用以下方法:

#include 
#include 
#include 

int Exa::create()
{
  pthread_t pt;
  ret=pthread_create(&pt,NULL,thread,(void*)this);//this为指向本对象的指针
}
void* Exa::thread(void *tmp)
{
  Exa *p=(Exa*)tmp;
  p->my_thread();  
}
void Exa::my_thread()
{
  printf("hey\n");
}

2.pthread_join()和pthread_exit()
函数pthread_join()为阻塞函数,用于等待一个线程运行结束。线程返回时,函数才会返回并且收回线程资源。

int pthread_join(
  pthread_t __th,
  void **__thread_return
);
__th:为线程标识符,即pthread_create()函数创建成功的值
__thread_return:指针,用于存储线程返回值

例如:

Exa::return()
{
  pthread_join(pt,NULL);
}

pthread_exit(),线程主动调用此函数退出。

void pthread_exit(void* ret);
ret:指针,指向线程退出的时候需要返回的值
线程互斥

由于同一进程中的所有线程共用资源,为防止两个线程使用资源时产生冲突,因此需要使用线程互斥锁。

初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
mutex: 互斥锁变量
mutexattr:互斥锁属性,设为NULL,表示默认属性

锁定互斥
int pthread_mutex_lock(pthread_mutex_t *mutex);

解锁互斥
int pthread_mutex_unlock(pthread_mutex_t *mutex);

销毁互斥
int pthread_mutex_destroy(pthread_mutex_t *mutex);

例如:

void Exa::my_thread()
{
  pthread_mutex_t mutex;
  pthread_mutex_init(&mutex,NULL);
  pthread_mutex_lock(&mutex);
  a=3;
  pthread_mutex_unlock(&mutex);
}
编译

由于pthread.h不是Linux的标准库,在使用G++编译时,要在最后加-lpthread参数

四、select()函数

select函数可以对文件描述符进行查询,查看文件描述符是否可进行读写操作。

#include 
#include 
#include 
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set *exceptfds, struct timeval *timeout);

nfds:监视的文件描述符集中,最大的文件描述符+1
readfds:监视该文件描述符集中的文件是否可以进行读操作
writefds:监视该文件描述符集中的文件是否可以进行写操作
exceptfds:监视该文件描述符集中是否有文件描述符发生错误,也可用于其他的用途
timeout:最长等待时间

有符合条件的事件发生时,返回值大于0;当超时时,返回0;发生错误时,返回-1,错误值存于errno。
操作文件描述符的宏:
FD_ZERO():将文件描述符集置为空
FD_SET():向某个文件描述符集中加入文件描述符
FD_CLR():向某个文件描述符集中去除文件描述符
FD_ISSET():测试某个文件描述符集中是否含有某个文件描述符

例如:

#include 
#include 
#include 
#include 
int main()
{
  fd_set rdfd;
  struct timeval tv;
  int err;

  FD_ZERO(rdfd);
  FD_SET(0,&rdfd);
  
  tv.tv_sec=5;//设置等待时间为5秒
  tv.tv_usec=0;
  err=select(1,&rdfd,NULL,NULL,&tv);
  if(err==-1)
  {
    printf("select error\n");
    return -1;
}
  else if(err==0)
  {
    printf("timed out\n");
    return -1;
  }
  else
  {
    printf("data available\n");
    return 0;
  }

注:调用select()函数后,结构体timeval的值会替换为剩余时间;如果文件描述符集中的某个文件描述符在超时前发生变化(可读\可写),该文件描述符在集中的位置会被置零,因此如果需要循环调用select()函数监控某一个文件描述符,每次调用select()函数之前都要重新初始化等待时间,并将需要监控的文件描述符加入文件描述符集。

五、pthread_cond_timedwait()函数

当sleep()延时不准确,不方便使用alarm()计时的时候,可以单独开始一个线程,使用pthread_cond_timedwait()进行计时。

int pthread_cond_init(
  pthread_cond_t *cv,
  const pthread_condattr_t *cattr);
cv:一个条件变量
cattr:属性,设为NULL为默认属性

int pthread_cond_timedwait(
  pthread_cond_t __cond,
  pthread_mutex_t __mutex,
  struct timespec __abstime
);
__cond:条件变量
__mutex:互斥锁
__adstime:等待时间

pthread_cond_timedwait()需要配合互斥锁使用,例如

void main()
{
  pthread_t thread1;
  pthread_t thread2;
  pthread_mutex_t mutex;
  pthread_cond_t m_cond;  

  pthread_mutex_init(&mutex,NULL);
  pthread_cond_init(&m_cond,NULL);
  pthread_create(&thread1,NULL,thread1,NULL);
  pthread_create(&thread2,NULL,thread2,NULL);
  usleep(1);
  pthread_join(thread1,NULL);
  pthread_join(thread2,NULL);   
  exit(0);
}
static void* thread1()
{
  pthread_mutex_lock(&mutex);
  gettimeofday(&now,NULL);
  m_time.tv_sec=now.tv_sec+10;
  m_time.tv_nsec=now.tv_usec*1000;
  ret=pthread_cond_timedwait(&m_cond,&mutex,&m_time);
  pthread_mutex_unlock(&mutex);
}
static void* thread2()
{
  pthread_mutex_lock(&mutex);
  gettimeofday(&now,NULL);
  m_time.tv_sec=now.tv_sec+10;
  m_time.tv_nsec=now.tv_usec*1000;
  ret=pthread_cond_timedwait(&m_cond,&mutex,&m_time);
  pthread_mutex_unlock(&mutex);
}

你可能感兴趣的:(project-te)