C++的多線程不同於C語言的多線程,對於我這個從C轉向C++的來說更是覺得很難理解;來新公司的這段時間也是一直在思考這方面的事情,近期一直在檢查程式中死結的問題;就總結以下最近對於C++多線程編程的心得吧。
C++的多線程主要體現在兩方面,一方面是對於全域資料的線程同步。我們看下面的執行個體
首先我們封裝一個Thread類
Thread.h 檔案
View Code
#ifndef THREAD_H
#define THREAD_H
#include <pthread.h>
class Thread
{
public:
Thread();
int start();
int stop();
virtual void* run();
bool join();
const pthread_t& getID()const { return ntid; }
virtual ~Thread(){};
private:
Thread(const Thread&);
static void* threadproc(void*);
pthread_t ntid;
};
Thread.cpp 檔案
View Code
#include <pthread.h>
#include "Thread.h"
Thread::Thread()
{
}
void* Thread::run()
{
}
int Thread::start()
{
return pthread_create(
&this->ntid,
0,
threadproc,
static_cast<void *>(this)
);
}
int Thread::stop()
{
return pthread_cancel(this->getID());
}
bool Thread::join()
{
return pthread_join(this->getID(),0);
}
void* Thread::threadproc(void* a_param)
{
Thread* pthread = static_cast<Thread *>(a_param);
return pthread->run();
然後我們建立MyThread類,繼承自Thread類,以實現不同的演算法。
MyThread.h
View Code
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <string>
#include "Thread.h"
class MyThread:public Thread
{
public:
MyThread(const int n,const char* aName):mCount(n),mName(aName){};
virtual void* run();
int setCount(const int n);
int setName(const char* aName);
private:
int mCount;
std::string mName;
};
MyThread.cpp
View Code
#include <string>
#include <stdio.h>
#include <boost/thread/thread.hpp>
#include "MyThread.h"
void* MyThread::run()
{
int sum = this->mCount*10;
for(int i = 0;i < sum ;i++)
{
printf("%2d,the name is %s;\t\n",i,this->mName.c_str());
}
}
int MyThread::setCount(const int n)
{
this->mCount = n;
return 0;
}
int MyThread::setName(const char* aName)
{
std::string aString(aName);
this->mName = aString;
return 0;
main.cpp
View Code
#include <stdio.h>
#include "MyThread.h"
int main()
{
MyThread t1(15,"Thread 1");
MyThread t2(12,"Thread 2");
t1.start();
t2.start();
sleep(1);
return 0;
Makefile檔案,寫的不好,大家見諒啊
View Code
multiThread:main.o MyThread.o Thread.o
g++ -o multiThread main.o MyThread.o Thread.o -lpthread
main.o:main.cpp MyThread.h
g++ -c main.cpp
MyThread.o:MyThread.cpp MyThread.h Thread.h
g++ -c MyThread.cpp
Thread.o:Thread.cpp Thread.h
g++ -c Thread.cpp
clean:
make並且運行之後,看下運行情況 為了節省空間的我只給出了幾個資料,有興趣大家可以展示以下
View Code
....
4,the name is Thread 1;
0,the name is Thread 2;
5,the name is Thread 1;
....
9,the name is Thread 1;
10,the name is Thread 1;
1,the name is Thread 2;
2,the name is Thread 2
線程1和2交替在終端列印,但是如果我們添加互斥量(相當於是對終端訪問的互斥量)之後會出現什麼情況呢?
我們修改MyThread.cpp檔案如下
View Code
#include <string>
#include <stdio.h>
#include <boost/thread/thread.hpp>
#include "MyThread.h"
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//添加互斥量
void* MyThread::run()
{
pthread_mutex_lock(&mutex); //加鎖
int sum = this->mCount*10;
for(int i = 0;i < sum ;i++)
{
printf("%2d,the name is %s;\t\n",i,this->mName.c_str());
}
pthread_mutex_unlock(&mutex); //解鎖
}
int MyThread::setCount(const int n)
{
this->mCount = n;
return 0;
}
int MyThread::setName(const char* aName)
{
std::string aString(aName);
this->mName = aString;
return 0;
我們可以運行一下看下列印資訊,沒有資料的衝突,因為資料量太大,在此不列出。
C++封裝的概念使不同對象之間的私人資料不會交錯,這個概念是我這個從C轉向C++一直無法理解,尤其是在遇見多線程的情況下,但是這並不表明私人資料不需要加鎖,因為可能涉及到類中不同的方法在同時訪問或者修改資料。看下面的例子
我們將main.cpp檔案修改如下,
View Code
#include <stdio.h>
#include "MyThread.h"
int main()
{
MyThread t1(150,"Thread 1");
//MyThread t2(12,"Thread 2");
t1.start();
t1.setCount(12);
//t2.start();
sleep(1);
return 0;
將MyThread.cpp檔案中的run函數也略作修改
View Code
#include <string>
#include <stdio.h>
#include <boost/thread/thread.hpp>
#include "MyThread.h"
void* MyThread::run()
{
for(int i = 0;i < this->mCount*10000 ;i++)
{
printf("%2d,the name is %s;\t\n",i,this->mName.c_str());
}
}
int MyThread::setCount(const int n)
{
this->mCount = n;
return 0;
}
int MyThread::setName(const char* aName)
{
std::string aString(aName);
this->mName = aString;
return 0;
大家可以看下運行結果,在這裡就不作詳細說明;
為瞭解決上述的衝突,我們需要在類中添加鎖,為了我們修改MyThread.h MyThread.cpp 和 main.cpp函數
MyThread.h檔案
View Code
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <string>
#include "Thread.h"
class MyThread:public Thread
{
public:
MyThread(const int n,const char* aName):mCount(n),mName(aName)
{
pthread_mutex_init(&mutex,NULL);
}
virtual void* run();
int setCount(const int n);
int setName(const char* aName);
private:
int mCount;
std::string mName;
pthread_mutex_t mutex;
};
MyThread.cpp檔案
View Code
#include <string>
#include <stdio.h>
#include <boost/thread/thread.hpp>
#include "MyThread.h"
void* MyThread::run()
{
pthread_mutex_lock(&mutex);
//int sum = this->mCount*10;
for(int i = 0;i < this->mCount*10000 ;i++)
{
printf("%2d,the name is %s;\t\n",i,this->mName.c_str());
}
pthread_mutex_unlock(&mutex);
}
int MyThread::setCount(const int n)
{
pthread_mutex_lock(&mutex);
this->mCount = n;
pthread_mutex_unlock(&mutex);
return 0;
}
int MyThread::setName(const char* aName)
{
std::string aString(aName);
this->mName = aString;
return 0;
main.cpp 檔案
View Code
#include <stdio.h>
#include "MyThread.h"
int main()
{
MyThread t1(150,"Thread 1");
t1.start();
sleep(1);
t1.setCount(12);
t1.start();
return 0;
有興趣的讀者可以看下運行效果,在添加了類內部鎖之後,有效實現了資料的同步。
歡迎討論。