⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atm_svr_cancel.c

📁 linux thread programe
💻 C
📖 第 1 页 / 共 2 页
字号:
/******************************************************** * An example source module to accompany... * * "Using POSIX Threads: Programming with Pthreads" *     by Brad nichols, Dick Buttlar, Jackie Farrell *     O'Reilly & Associates, Inc. * ******************************************************** * atm_srv_cancel.c * * Variant using pthread cancellation for shutdown of  * multi-threaded server for the ATM example. * Maintains a database of bank accounts accepting requests from * client programs to perform transactions on them. */#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <pthread.h>#include "atm.h"#include "atm_com.h"#include "atm_db.h"#include "atm_svr_password.h"static char atm_err_tbl[ERR_MSG_TBL_SIZE][ERR_MSG_SIZE];#define MAX_NUM_THREADS 10typedef struct workorder {  int  conn;                     char req_buf[COMM_BUF_SIZE]; } workorder_t;          /* Structure used to pass infomation to a worker thread.	     Contains what a thread needs to know to execute the 	     process_request() routine. Note that a struct is used 	     because the syntax of a pthread_create() only allows a single	     argument to be passed to the routine being executed 	     by the starting thread. */typedef struct {  int             num_active;  pthread_cond_t  thread_exit_cv;  pthread_mutex_t mutex;} thread_info_t;thread_info_t pthread_info;         /* Structure used by main() thread to keep track of the number of	    active threads. Used to limit how many threads it will create 	    and under a shutdown condition to wait till all in-progress	    requests have finished before "turning off the lights". *//* Database Account Access Synchronization Options, uncomment on of the    following; *//* #define NO_DATABASE_SYNC *//* #define SINGLE_DATABASE_MUTEX_SYNC */#define ACCOUNT_MUTEX_SYNC #ifdef NO_DATABASE_SYNC                                                 /* No synchronization, 						    account data may be 						    corrupted by race						    conditions */#elif defined(SINGLE_DATABASE_MUTEX_SYNC)pthread_mutex_t global_data_mutex=PTHREAD_MUTEX_INITIALIZER;                                            /* Single mutex that controls                                               access to all database 					       accounts. */         /* Mutex used in the Single Database Mutex Option	    To control (synchronize) concurrent access by multiple	    threads to the database this options defines a single	    mutex that any thread must hold before entering the database 	    module. Advantages: Simple, non-change to underlying package 	    (esp. nice if all we have is a library that we can't modify).	    Disadvantages: No concurrency in database. all threads block. */#elif defined(ACCOUNT_MUTEX_SYNC)pthread_mutex_t account_mutex[MAX_NUM_ACCOUNTS]; /* Array of mutex, one per						    database account. */pthread_mutex_t open_account_mutex=PTHREAD_MUTEX_INITIALIZER;                                                 /* Special case mutex,						    controls access to creating						    new account in database. */#endifworkorder_t *workorderp;      /* a structure containing the                                 information a worker thread                                 needs to go off and process                                 a request. *//* Forward declarations of routines */void *process_request(void *);void atm_server_init(int, char **);void open_account(char *);void deposit(char *, char *);void withdraw(char *, char *);void balance(char *, char *);int  shutdown_req(char *, char *);void handle_bad_trans_id(char *, char *);pthread_t   *worker_threadp;   /* a pointer to a newly created thread 				   object. In this example, the main()				   thread and none of the worker threads				   need to have a handle to anyother thread.				   So here never store a pre-thread handle and				   reuse this pointer no matter how many				   threads are currently active.				   An example where we might need to maintain				   a set of handles for all active threads				   would be if we used the cancellation				   mechanism or join. *//**************************************************************************  * main() * Basic processing loop of the bank database server. * The program initializies the database then loops, accepting * transaction requests from clients. ***************************************************************************/extern intmain(int argc, char **argv){  int  trans_id;                /* The transaction type of the current 				   request */  void *status;  atm_server_init(argc, argv);  for(;;) {    /*** Wait for a request ***/    DPRINTF(("SERVER: main(), going to get a request\n"));    workorderp = (workorder_t *)malloc(sizeof(workorder_t));    server_comm_get_request(&workorderp->conn, workorderp->req_buf);    DPRINTF(("SERVER: main(), got a request\n"));    /*** Is it a shutdown request? ***/    sscanf(workorderp->req_buf, "%d", &trans_id);    if (trans_id == SHUTDOWN) {      char resp_buf[COMM_BUF_SIZE];      DPRINTF(("SERVER: main(), processing a shutdown request\n"));      pthread_mutex_lock(&pthread_info.mutex);      /* Wait for in-progress requests threads to finish */      while (pthread_info.num_active > 0) {	pthread_cond_wait(&pthread_info.thread_exit_cv, &pthread_info.mutex);      }      pthread_mutex_unlock(&pthread_info.mutex);      /* process it here with main() thread */      if (shutdown_req(workorderp->req_buf, resp_buf)) {	server_comm_send_response(workorderp->conn, resp_buf);	free(workorderp);	break;      }    }        /*** Have we exceeded our limit of active threads ? ***/    pthread_mutex_lock(&pthread_info.mutex);    DPRINTF(("SERVER: main(), num_active %d\n", pthread_info.num_active));    while (pthread_info.num_active == MAX_NUM_THREADS) {      DPRINTF(("SERVER: main(), num_active %d, waiting for a thread to exit\n",	     pthread_info.num_active));      pthread_cond_wait(&pthread_info.thread_exit_cv, &pthread_info.mutex);    }    pthread_info.num_active++;    pthread_mutex_unlock(&pthread_info.mutex);    /*** Spawn a thread to process this request ***/    DPRINTF(("SERVER: main(), spawing worker thread\n"));    worker_threadp = (pthread_t *)malloc(sizeof(pthread_t));    pthread_create(worker_threadp,  		   NULL,                    /* Use default attributes */		   process_request,  	 	   (void *) workorderp );    pthread_detach(*worker_threadp);  }  DPRINTF(("SERVER: main(), shuting down\n"));  server_comm_shutdown();  return 0;}/*************************************************************************  * Base worker routine * * Thread looks at workorder req_buf field to determine requested operation. * Executes assoicated account routine, sends response back to client and * then will do an implicit exit when this routine finishes. *************************************************************************/void *process_request(void *input_orderp){  workorder_t *workorderp = (workorder_t *)input_orderp;  char resp_buf[COMM_BUF_SIZE];  int  trans_id;                /* The transaction type of the request */  /* Defered cancellation is enabled, arrange cleanup */  pthread_cleanup_push(free, input_orderp);   DPRINTF(("SERVER worker thread: processing request \n"));  sscanf(workorderp->req_buf, "%d", &trans_id);    DPRINTF(("SERVER worker thread: processing request \n"));   pthread_testcancel();  switch(trans_id) {          case OPEN_ACCT_TRANS:           open_account(resp_buf);           break;      case DEPOSIT_TRANS:	   deposit(workorderp->req_buf, resp_buf);	   break;      case WITHDRAW_TRANS:	   withdraw(workorderp->req_buf, resp_buf);	   break;      case BALANCE_TRANS:	   balance(workorderp->req_buf, resp_buf);	   break;      default: 	   handle_bad_trans_id(workorderp->req_buf, resp_buf);	   break;      }  pthread_testcancel(); /* the transaction routine may have disabled			   cancellation by this point, but it won't			   hurt anything to check it either way */  server_comm_send_response(workorderp->conn, resp_buf);  pthread_cleanup_pop(1); /* free the workorder buffer */      DPRINTF(("SERVER worker thread: response sent\n"));  pthread_mutex_lock(&pthread_info.mutex);  pthread_info.num_active--;  pthread_cond_signal(&pthread_info.thread_exit_cv);  pthread_mutex_unlock(&pthread_info.mutex);  return(NULL);}/*************************************************************************  * Initializes server *************************************************************************/void atm_server_init(int argc, char **argv){  int i, rtn;  int force_create = 0;  int increased_io = 0;  int increased_cpu = 0;  /* process input arguments */  if (argc >= 4) sscanf(argv[3], "%d", &increased_cpu);  if (argc >= 3) sscanf(argv[2], "%d", &increased_io);   if (argc >= 2) {    if ((rtn = strcmp(argv[1], "-c")) == 0)      force_create = 1;    if (((rtn = strcmp(argv[1], "-h")) == 0) || 	((rtn = strcmp(argv[1], "h")) == 0)  ||		((rtn = strcmp(argv[1], "help")) == 0)) {      printf("  %s [-c] [increased_io increased_cpu]\n", argv[0]);      printf("\t-c\t\tcreate a new database\n");      printf("\tincreased_io\tadd extra io work to storing a account\n");      printf("\tincreased_cpu\tadd extra cpu work to storing an account\n");      exit(1);    }  }#ifdef NO_DATABASE_SYNC  printf("\t%s: USING NO SYNCHRONIZATION TO ACCOUNTS\n", argv[0]);#endif#ifdef SINGLE_DATABASE_MUTEX_SYNC  printf("\t%s: USING ONE LOCK FOR ALL ACCOUNTS\n", argv[0]);#endif  /* Initialize error translation table. */   sprintf(atm_err_tbl[-1*ERR_NUM_NO_ACCOUNTS],  "%s", ERR_MSG_NO_ACCOUNTS);  sprintf(atm_err_tbl[-1*ERR_NUM_DATA_UNAVAIL], "%s", ERR_MSG_DATA_UNAVAIL);  sprintf(atm_err_tbl[-1*ERR_NUM_BAD_ACCOUNT],  "%s", ERR_MSG_BAD_ACCOUNT);  sprintf(atm_err_tbl[-1*ERR_NUM_BAD_PASSWORD], "%s", ERR_MSG_BAD_PASSWORD);  sprintf(atm_err_tbl[-1*ERR_NUM_INS_FUNDS],    "%s", ERR_MSG_INS_FUNDS);  sprintf(atm_err_tbl[-1*ERR_NUM_BAD_TRANSID],  "%s", ERR_MSG_BAD_TRANSID);  pthread_info.num_active = 0;  pthread_cond_init(&pthread_info.thread_exit_cv, NULL); /* Use default attr */  pthread_mutex_init(&pthread_info.mutex, NULL); /* Use default attr */#ifdef NO_DATABASE_SYNC  DPRINTF(("atm server using no database synchronization\n"));#elif defined(SINGLE_DATABASE_MUTEX_SYNC)  DPRINTF(("atm server using single mutex database synchronization\n")); #elif defined(ACCOUNT_MUTEX_SYNC)  for (i = 0; i < MAX_NUM_ACCOUNTS; i++)    pthread_mutex_init(&account_mutex[i], NULL);  DPRINTF(("atm server using per account mutex database synchronization\n")); #endif  init_account_db(force_create, increased_io, increased_cpu);    server_comm_init();  server_password_init(force_create);}/************************************************************************** * Open an account. The first unused account is selected. A password  * equal to the account number is assigned by the server. **************************************************************************/void open_account(char *resp_buf){  int id;  int rtn;  account_t *accountp;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -