1、动态库只有一个导出函数。
这种情况下编写函数时,只需要考虑不要有冲突的全局数据就可以了。这里的全局数据包括了在堆中分配的数据块和静态全局变量等。如果存在这样的全局数据,那么进程中的不同线程访问这个函数就会造成冲突。
2、动态库导出了多个函数,而且多个函数间存在数据传递。
一般DLL都导出多个函数,一个初始化,一个资源释放,其他为核心功能函数。这些函数间极有可能发生数据传递。如果一个初始化函数是在线程A中调用的,而核心功能函数是在线程B中调用的,那么线程A初始化函数的资源就无法对应线程B中的核心功能,此外还有核心功能函数间的数据传递,这样的DLL就不是线程安全的,必然导致错误。
解决办法是由用户(即使用DLL的人)保证这些导出函数是在一个线程中调用。但这样会很大程度上限制接口的设计和用户的使用自由度。所以最好的方法是函数只管自己的线程安全,不同函数传递数据用动态TLS,线程局部存储。
3、限制访问DLL中某一函数的线程数目。
对于DLL中的某一个函数的访问线程数目是有限制的,超过了限制其他线程就得等一定的时间,一定的时间过后如果还不能得到执行机会,那就返回超时。这样的设计对用户来说是友好的,而且很实用,有的商业程序确实是按照允许用户访问的通道数目来计价的。
对DLL中的函数做这样的一个封装,一般是简单的待用Semaphore信号量,来解决。DLL初始化时调用CreateSemaphore函数对信号量进行初始化,其原型如下:
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
// pointer to security attributes
LONG lInitialCount, // initial count
LONG lMaximumCount, // maximum count
LPCTSTR lpName // pointer to semaphore-object name
)
对于信号量,它每WaitForSingleObject一次(当然是要进入),其状态值(一个整数)就减1,使用完ReleaseSemaphore其状态值就加1,当其状态值为0时信号量就由有信号变为无信号。利用信号量的这一特性,我们在初始化时将信号量的初始值(第2个参数)设置为限制的线程访问数目。在要限制访问线程数目的函数内部,通过调用WaitForSingleOject获取控制权,并指定一个等待时间(这个由配置文件指定),根据情况超时返回,使用完ReleaseSemaphore释放对占用,让其他线程可以调用这个函数。
4、多进程情况下的多线程安全DLL。
LL是可以被多个进行加载并调用的。那就是说如果我们只对一个进程进行了限制,那么在多进程调用的情况下,这样的限制被轻易攻破。
我们都知道,Semaphore信号量属于内核对象,也就是说其可以被多进程共享访问,也就说,如果我们给一个Semaphore指定了一个名字,在另一个进程中,我们只要调用OpenSemaphore函数用同一名字打开信号量就可以访问了。这样问题就解决了?
现实情况是,多进程情况下,一般不是简单的多进程共享一个Semaphore就可以了。多进程间需要互通很多信息。一般的解决办法是,采用共享数据段。
#pragma data_seg("share")
int share_data
#pragma data_seg()
#pragma comment(linker,"/SECTION:share, RWS")
通过pragam编译器指令生成了一个名叫share的共享数据段,这样对于变量share_data就可以多进程共享的了。如果要多进程间交换数据,只要在data_seg中添加数据定义即可。
#ifndef THREAD_H_#define THREAD_H_
#include <unistd.h>
#include <pthread.h>
class Runnable
{
public:
//运行实体
virtual void run() = 0
}
//线程类
class Thread: public Runnable
{
private:
//线程初始化号
static int thread_init_number
//当前线程初始化序号
int current_thread_init_number
//线程体
Runnable *target
//当前线程的线程ID
pthread_t tid
//线程的状态
int thread_status
//线程属性
pthread_attr_t attr
//线程优先级
sched_param param
//获取执行方法的指针
static void* run0(void* pVoid)
//内部执行方法
void* run1()
//获取线程序号
static int get_next_thread_num()
public:
//线程的状态-新建
static const int THREAD_STATUS_NEW = 0
//线程的状态-正在运行
static const int THREAD_STATUS_RUNNING = 1
//线程的状态-运行结束
static const int THREAD_STATUS_EXIT = -1
//构造函数
Thread()
//构造函数
Thread(Runnable *target)
//析构
~Thread()
//线程的运行体
void run()
//开始执行线程
bool start()
//获取线程状态
int get_state()
//等待线程直至退出
void join()
//等待线程退出或者超时
void join(unsigned long millis_time)
//比较两个线程时候相同,通过current_thread_init_number判断
bool operator ==(const Thread* other_pthread)
//获取this线程ID
pthread_t get_thread_id()
//获取当前线程ID
static pthread_t get_current_thread_id()
//当前线程是否和某个线程相等,通过tid判断
static bool is_equals(Thread* iTarget)
//设置线程的类型:绑定/非绑定
void set_thread_scope(bool isSystem)
//获取线程的类型:绑定/非绑定
bool get_thread_scope()
//设置线程的优先级,1-99,其中99为实时,意外的为普通
void set_thread_priority(int priority)
//获取线程的优先级
int get_thread_priority()
}
int Thread::thread_init_number = 1
inline int Thread::get_next_thread_num()
{
return thread_init_number++
}
void* Thread::run0(void* pVoid)
{
Thread* p = (Thread*) pVoid
p->run1()
return p
}
void* Thread::run1()
{
thread_status = THREAD_STATUS_RUNNING
tid = pthread_self()
run()
thread_status = THREAD_STATUS_EXIT
tid = 0
pthread_exit(NULL)
}
void Thread::run()
{
if (target != NULL)
{
(*target).run()
}
}
Thread::Thread()
{
tid = 0
thread_status = THREAD_STATUS_NEW
current_thread_init_number = get_next_thread_num()
pthread_attr_init(&attr)
}
Thread::Thread(Runnable *iTarget)
{
target = iTarget
tid = 0
thread_status = THREAD_STATUS_NEW
current_thread_init_number = get_next_thread_num()
pthread_attr_init(&attr)
}
Thread::~Thread()
{
pthread_attr_destroy(&attr)
}
bool Thread::start()
{
return pthread_create(&tid, &attr, run0, this)
}
inline pthread_t Thread::get_current_thread_id()
{
return pthread_self()
}
inline pthread_t Thread::get_thread_id()
{
return tid
}
inline int Thread::get_state()
{
return thread_status
}
void Thread::join()
{
if (tid > 0)
{
pthread_join(tid,NULL)
}
}
void Thread::join(unsigned long millis_time)
{
if (tid == 0)
{
return
}
if (millis_time == 0)
{
join()
}
else
{
unsigned long k = 0
while (thread_status != THREAD_STATUS_EXIT && k <= millis_time)
{
usleep(100)
k++
}
}
}
bool Thread::operator ==(const Thread* other_pthread)
{
if(other_pthread==NULL)
{
return false
}if(current_thread_init_number==(*other_pthread).current_thread_init_number)
{
return true
}
return false
}
bool Thread::is_equals(Thread* iTarget)
{
if (iTarget == NULL)
{
return false
}
return pthread_self() == iTarget->tid
}
void Thread::set_thread_scope(bool isSystem)
{
if (isSystem)
{
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)
}
else
{
pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS)
}
}
void Thread::set_thread_priority(int priority)
{
pthread_attr_getschedparam(&attr,&param)
param.__sched_priority = priority
pthread_attr_setschedparam(&attr,&param)
}
int Thread::get_thread_priority(){
pthread_attr_getschedparam(&attr,&param)
return param.__sched_priority
}
#endif /* THREAD_H_ */
线程的实现有user level thread,kernel-level thread和两者结合的方式。Linux的实现了kernel-level thread,共享进程地址空间的进程相当于线程。PThread是user level thread,内核根本不了解其线程的存在,不会对其中的线程进行调度,更不会对其进行代码实现。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)