首页 > 技术文章 > OCCI线程安全

Focus-Flying 2018-07-09 11:49 原文

线程是任务调度的基本单位,一个进程中可以有多个线程,每个线程有自己的堆栈空间,
进程中的代码段、数据段和堆栈对进程中的线程是可见的。在使用线程时通常都要考虑数据的安全访问。
常用的线程同步方法有:

  • 互斥变量
  • 读写锁
  • 条件变量
  • 屏障
  • 自旋锁(用于CPU,锁住后CPU将不执行其他事情,即一直等待)

在OCCI程序中使能线程安全,则应指定THREADED_MUTEXED选项创建运行环境

例如:
	Environment *env =
		 Environment::createEnvironment(Environment::THREADED_MUTEXED)

注意:

  • 如果应用程序是单线程,则使用默认值创建环境即可;
    如果指定THREADED_MUTEXED选项创建将会影响应用程序性能。
  • OCCI中的线程安全仅仅指的是EnvironmentMapConnectionPool
    StatelessConnectionPoolConnection对象。对于StatementResultSet
    SQLExceptionStream等不是线程安全的,因此不应该在多个线程中共享。

以下例子创建一个只有一个连接的无状态连接池,创建两个线程去竞争从池中得到连接
当以线程安全创建环境时程序运行正常,当使用默认选项创建环境时,程序将抛出异常:

what():  ORA-03117: two-task save area overflow
#include <iostream>
#include <cstdlib>

#include <pthread.h>
#include <unistd.h>
#include <occi.h>


#define USERNAME	"scott"
#define PASSWORD	"scott"
#define DBNAME		"//192.168.42.135:1521/orcl"
#define MAXCON	1
#define MINCON	0
#define INCCON	1	


using namespace oracle::occi;
using namespace std;

void *displayAllRows(void *arg);
void *updateRow(void *arg);


int main(void)
{
	Environment *env = Environment::createEnvironment(Environment::THREADED_MUTEXED);

	//创建无状态连接池
	StatelessConnectionPool *scp = 
		env->createStatelessConnectionPool(
			USERNAME, PASSWORD, DBNAME, MAXCON, MINCON, INCCON,
			StatelessConnectionPool::HOMOGENEOUS);
	
	//设置池中的连接空闲超时时间,超时后OCCI会自动释放此连接,需要时在创建
	scp->setTimeOut(10);
	

	cout << "*****************Information**************************" << endl;
	cout << "Open Connection : " << scp->getOpenConnections() << endl;
	cout << "Busy Connection : " << scp->getBusyConnections() << endl;
	cout << "Time Out Connection : " << scp->getTimeOut() << endl;
	cout << "******************************************************" << endl;


	pthread_t tid_1, tid_2;
	int err = 0;
	err = pthread_create(&tid_1, NULL, displayAllRows, (void *)scp);
	if (err != 0) {
		cout << "create thread failure for tid_1." << endl;
	} else {
		cout << ">> create thread successful for tid_1." << endl;
	}

	err = pthread_create(&tid_2, NULL, updateRow, (void *)scp);
	if (err != 0) {
		cout << "create thread failure for tid_2." << endl;
	} else {
		cout << ">> create thread successful for tid_2." << endl;
	}

	pthread_join(tid_1, (void **)NULL);
	pthread_join(tid_2, (void **)NULL);


	env->terminateStatelessConnectionPool(scp);
	Environment::terminateEnvironment(env);

	return 0;
}


void *displayAllRows(void *arg)
{
	StatelessConnectionPool *scp = (StatelessConnectionPool *)arg;


	for ( ; ; )
	{
		std::cout << ">>>> displayAllRows thread runing [" << long(pthread_self()) << "]" << std::endl;

		Connection *conn = scp->getConnection("");
		
		string sqlStmt = "SELECT * FROM DEPT WHERE DEPTNO=60";
		
		Statement *stmt = conn->createStatement(sqlStmt);
		
		ResultSet *rset = stmt->executeQuery();
	
		try {
			while (rset->next()) {
				cout << int(rset->getNumber(1)) << "	";
				cout << rset->getString(2) << "	";
				cout << rset->getString(3) << "	";
				cout << endl;
			}
		}catch(SQLException &ex) {
			cout << "display all rows failure." << endl;
			cout << ex.getMessage();
			cout << endl;
		}
	
		sleep(5);

		stmt->closeResultSet(rset);
		conn->terminateStatement(stmt);
		scp->releaseConnection(conn, "");
	}

	pthread_exit((void *)0);
}

void *updateRow(void *arg)
{
	StatelessConnectionPool *scp = (StatelessConnectionPool*)arg;


	for ( ; ; )
	{
		std::cout << ">>> updateRow thread running [" << long(pthread_self()) << "]" << std::endl;

		Connection *conn = scp->getConnection("");
		
		string sqlStmt = "UPDATE DEPT SET LOC=:deptLocal WHERE DEPTNO=51";

		Statement *stmt = conn->createStatement(sqlStmt);

		try {
			stmt->setString(1, "ShangHai");
			stmt->executeUpdate();
			conn->commit();
		} catch(SQLException &ex) {
			cout << "update row failure." << endl;
			cout << ex.getMessage();
			cout << endl;
		}

		conn->terminateStatement(stmt);
		scp->releaseConnection(conn, "");

		sleep(1);
	}

	pthread_exit((void *)0);
}

推荐阅读