muduo 之线程(13)


线程的标示

线程标识符
    pthread_self
gettid
    __thread,gcc内置的线程局部存储设施
    __thread只能修饰POD类型
POD类型(plain old data),与C兼容的原始数据,例如,结构和整型等C语言中的类型是 POD 类型,但带有用户定义的构造函数或虚函数的类则不是
    __thread string t_obj1(“cppcourse”);    // 错误,不能调用对象的构造函数
    __thread string* t_obj2 = new string;    // 错误,初始化只能是编译期常量
    __thread string* t_obj3 = NULL;    // 正确
    boost::is_same
    pthread_atfork




  • Linux中,每个进程有一个pid,类型pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id由线程库维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)。Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。

  • 有时候我们可能需要知道线程的真实pid。比如进程P1要向另外一个进程P2中的某个线程发送信号时,既不能使用P2的pid,更不能使用线程的pthread id,而只能使用该线程的真实pid,称为tid。

  • 有一个函数gettid()可以得到tid,但glibc并没有实现该函数,只能通过Linux的系统调用syscall来获取。
    return syscall(SYS_gettid)


muduo库的Thread类图


-started_:bool
 
-pthreadId : pthread_t
 
-tid_:pid_t//
 
-func_:ThreadFunc
 
-name_:string //线程的名称
 
-numCreated_:AtomicInt32 //已经创建线程的个数
 
-------------------------------
 
<<create>>+Thread(func:const ThreadFunc&,name:string)
 
<<destroy>>+Thread()
 
+start():void
 
+join():int
 
+started():bool //线程是否已经启动了
 
+tid():pid_t
 
+name():const string &
 
+numCreated():int //已近启动线程的个数
 
-startThread(thread:void):void *
 
-runInThread():void
 
-----------------------------------------------------------------------
 
函数调用关系
 
startThread()--->runInthread--->func

源文件


头文件:Thread.h

namespace muduo
{
 
class Thread : boost::noncopyable
{
 public:
  typedef boost::function<void ()> ThreadFunc;
 
  explicit Thread(const ThreadFunc&, const string& name = string());
  ~Thread();
 
  void start();
  int join(); // return pthread_join()
 
  bool started() const { return started_; }
  // pthread_t pthreadId() const { return pthreadId_; }
  pid_t tid() const { return tid_; }
  const string& name() const { return name_; }
 
  static int numCreated() { return numCreated_.get(); }
 
 private:
  static void* startThread(void* thread);
  void runInThread();
 
  bool       started_;
  pthread_t  pthreadId_;
  pid_t      tid_;
  ThreadFunc func_;
  string     name_;
 
  static AtomicInt32 numCreated_;
};
 
}
#endif

源文件:Thread.cpp

namespace muduo
{
namespace CurrentThread
{ // __thread修饰的变量时线程局部存储的。 也就是所个线程都一份
  __thread int t_cachedTid = 0; //线程真实pid(tid)的缓存,如果每次都使用syscall(SYS_gettid)来获取tid,那么效率会很低
  __thread char t_tidString[32];//这是tid的字符串表示形式
  __thread const char* t_threadName = "unknown";
  const bool sameType = boost::is_same<int, pid_t>::value;
  BOOST_STATIC_ASSERT(sameType);
}
 
namespace detail
{
 
pid_t gettid()
{
  return static_cast<pid_t>(::syscall(SYS_gettid));
}
 
void afterFork()
{
  muduo::CurrentThread::t_cachedTid = 0;
  muduo::CurrentThread::t_threadName = "main";
  CurrentThread::tid();
  // no need to call pthread_atfork(NULL, NULL, &afterFork);
}
 
class ThreadNameInitializer
{
 public:
  ThreadNameInitializer()
  {
    muduo::CurrentThread::t_threadName = "main";
    CurrentThread::tid();
    pthread_atfork(NULL, NULL, &afterFork);
  }
};
 
ThreadNameInitializer init;
}
}
 
using namespace muduo;
 
void CurrentThread::cacheTid()
{
  if (t_cachedTid == 0)
  {
    t_cachedTid = detail::gettid();
    int n = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
    assert(n == 6); (void) n;
  }
}
 
bool CurrentThread::isMainThread()
{
  return tid() == ::getpid();
}
 
AtomicInt32 Thread::numCreated_;
 
Thread::Thread(const ThreadFunc& func, const string& n)
  : started_(false),
    pthreadId_(0),
    tid_(0),
    func_(func),
    name_(n)
{
  numCreated_.increment();
}
 
Thread::~Thread()
{
  // no join
}
 
void Thread::start()
{
  assert(!started_);
  started_ = true;
  errno = pthread_create(&pthreadId_, NULL, &startThread, this);
  if (errno != 0)
  {
    LOG_SYSFATAL << "Failed in pthread_create";
  }
}
 
int Thread::join()
{
  assert(started_);
  return pthread_join(pthreadId_, NULL);
}
 
void* Thread::startThread(void* obj)
{
  Thread* thread = static_cast<Thread*>(obj);
  thread->runInThread();
  return NULL;
}
 
void Thread::runInThread()
{
  tid_ = CurrentThread::tid();
  muduo::CurrentThread::t_threadName = name_.c_str();
  try
  {
    func_();
    muduo::CurrentThread::t_threadName = "finished";
  }
  catch (const Exception& ex)
  {
    muduo::CurrentThread::t_threadName = "crashed";
    fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
    fprintf(stderr, "reason: %s\n", ex.what());
    fprintf(stderr, "stack trace: %s\n", ex.stackTrace());
    abort();
  }
  catch (const std::exception& ex)
  {
    muduo::CurrentThread::t_threadName = "crashed";
    fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
    fprintf(stderr, "reason: %s\n", ex.what());
    abort();
  }
  catch (...)
  {
    muduo::CurrentThread::t_threadName = "crashed";
    fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str());
    throw; // rethrow
  }
}


测试程序1 :

#include <muduo/base/Thread.h>
#include <muduo/base/CurrentThread.h>
 
#include <string>
#include <boost/bind.hpp>
#include <stdio.h>
 
void threadFunc()
{
  printf("tid=%d\n", muduo::CurrentThread::tid());
}
 
void threadFunc2(int x)
{
  printf("tid=%d, x=%d\n", muduo::CurrentThread::tid(), x);
}
 
class Foo
{
 public:
  explicit Foo(double x)
    : x_(x)
  {
  }
 
  void memberFunc()
  {
    printf("tid=%d, Foo::x_=%f\n", muduo::CurrentThread::tid(), x_);
  }
 
  void memberFunc2(const std::string& text)
  {
    printf("tid=%d, Foo::x_=%f, text=%s\n", muduo::CurrentThread::tid(), x_, text.c_str());
  }
 
 private:
  double x_;
};
 
int main()
{
  printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid());
 
  muduo::Thread t1(threadFunc);
  t1.start();
  t1.join();
 
  muduo::Thread t2(boost::bind(threadFunc2, 42),
                   "thread for free function with argument");
  t2.start();
  t2.join();
 
  Foo foo(87.53);
  muduo::Thread t3(boost::bind(&Foo::memberFunc, &foo),
                   "thread for member function without argument");
  t3.start();
  t3.join();
 
  muduo::Thread t4(boost::bind(&Foo::memberFunc2, boost::ref(foo), std::string("Shuo Chen")));
  t4.start();
  t4.join();
 
  printf("number of created threads %d\n", muduo::Thread::numCreated());

程序输出

[root@localhost bin]# ./thread_test 
pid=3133, tid=3133
tid=3134
tid=3135, x=42
tid=3136, Foo::x_=87.530000
tid=3137, Foo::x_=87.530000, text=Shuo Chen
number of created threads 4
[root@localhost bin]# ^C

pthread_atfork

#include <pthread.h>
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
    调用fork时,内部创建子进程前在父进程中会调用prepare,内部创建子进程成功后,父进程会调用parent ,子进程会调用child


测试源码:

#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
 
void prepare(void)
{
    printf("pid = %d prepare ...\n", static_cast<int>(getpid()));
}
 
void parent(void)
{
    printf("pid = %d parent ...\n", static_cast<int>(getpid()));
}
 
void child(void)
{
    printf("pid = %d child ...\n", static_cast<int>(getpid()));
}
 
 
int main(void)
{
    printf("pid = %d Entering main ...\n", static_cast<int>(getpid()));
 
    pthread_atfork(prepare, parent, child);
 
    fork();
 
    printf("pid = %d Exiting main ...\n",static_cast<int>(getpid()));
 
    return 0;
}

程序输出

[root@localhost bin]# ./pthread_atfork_test 
pid = 3358 Entering main ...
pid = 3358 prepare ...
pid = 3358 parent ...
pid = 3358 Exiting main ...
[root@localhost bin]# pid = 3359 child ...
pid = 3359 Exiting main ...
 
[root@localhost bin]# ^C

注意:

在编程时要特别注意,不要使用多线程和多进程进行交叉使用,很有可能出现死锁的情况!!!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值