13.1.2 pthread_unlock_global_np 与 pthread_lock_globak_np的使用方法类似,只不过是用于对全局互斥体的解锁操作,略。
13.1.3 pthread_mutex_init 互斥体初始化语法:
#include int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
或
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
功能:对互斥体进行初始化。如果 attr参数调为 NULL,互斥体属性将会设置成为默认参数。当已具备如下定义后:
pthread_mutex_t mutex2; pthread_mutex_t mutex3; pthread_mutexattr_t mta;
pthread_mutexattr_init(&mta);
下面这三种对互斥体进行初始化的方法是等价的,它们都将互斥体初始化为默认属性。
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_init(&mutex2, NULL); pthread_mutex_init(&mutex3, &mta); 但是使用 PTHREAD_MUTEX_INITIALIZER这种方式对互斥体进行初始化,将不会立
刻生效,而是在其后首次使用 pthread_mutex_lock或 pthread_mutex_trylock函数时才会进行互斥体初始化。这是因为一个互斥体并不仅仅只是一个存储目标,它还需要系统分配相应的资源。于是,用这种方法对互斥体进行初始化,如果在互斥体没有被锁住时就执行 pthread_mutex_destroy,或 pthread_mutex_unlock操作,系统将会报一个 EINVAL的错误信息。
参数:
mutex
一个互斥体目标的地址。
Attr 标识互斥体属性目标的地址。(即互斥体属性结构体的地址位),可以为 NULL
返回: 0 --成功非 0 --失败
例子:略
13.1.4 pthread_mutex_lock 互斥体锁语法:
#include int pthread_mutex_lock(pthread_mutex_t *mutex)
功能:
当一个线程对互斥体成功执行了 pthread_mutex_lock操作后,其它的线程再对这个互斥体执行 lock操作时,将会被阻塞,直到当前线程对互斥体进行 unlock操作。然后就会有另一个等待执行 lock操作的线程再对互斥体进行 lock操作。参数:
mutex
要锁住的互斥体的地址。返回: 0 成功;非 0 失败
例子:下面这个例子中,通过使用互斥体,实现各个子线程实际上的串行。当没有调用参数时,程序会使用互斥体,来实际各个子线程实际上的串行,达到对关键
数据保护的目的,最后将会计算得出预期中正确的结果。如果有调用参数(随便什么参数均可),则程序将不会使用互斥体,子线程之间并行,对关键数据没有保护,此时将会计算出一个非预期的随机的错误结果。
#include #include #define checkResults(string, val) { \
if(val){ \ printf("Failed with %d at %s", val, string); \
exit(1); \ } \ } #define LOOPCONSTANT 10000 #define THREADS 10
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int i,j,k,l; int uselock=1;
void *threadfunc(void *parm)
{ int loop = 0; int rc;
for (loop=0; loop<LOOPCONSTANT; ++loop) {
if (uselock) { rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc);
} ++i; ++j; ++k; ++l; if (uselock) {
rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc);
} } return NULL;
}
int main(int argc, char **argv) { pthread_t threadid[THREADS];
int rc=0; int loop=0; pthread_attr_t pta;
printf("Entering testcase\n"); printf("Give any number of parameters to show data corruption\n"); if (argc != 1) {
printf("A parameter was specified, no serialization is being done!\n"); uselock = 0; }
pthread_attr_init(&pta); pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_JOINABLE);
printf("Creating %d threads\n", THREADS);
for (loop=0; loop<THREADS; ++loop) { rc = pthread_create(&threadid[loop], &pta, threadfunc, NULL); checkResults("pthread_create()\n", rc);
}
printf("Wait for results\n");
for (loop=0; loop%d, %d, %d, %d\n", i, j, k, l);
printf("Main completed\n"); return 0; }
13.1.5 pthread_mutex_unlock 互斥体解锁与 pthread_mutex_lock类似,只不过是解锁指令,略
13.1.6 pthread_mutex_destroy 销毁互斥体语法:
#include int pthread_mutex_destroy(pthread_mutex_t *mutex)
功能:销毁指定的互斥体,销毁后的互斥体将不能再使用。互斥体只能由它的拥有者来销毁,如果别的线程锁住互斥体,当前线程执行
pthread_mutex_destroy函数时,将会得到一个 EBUSY的错误信息。
如果销毁互斥体时,其它的通过调用 pthread_mutex_lock函数,正处于阻塞状态中的线程将会由系统返回信息,并得到一个 EDESTROYED的错误信息。参数:
mutex
互斥体结构的地址。返回: 0 –正常;非 0 --失败例子:见 pthread_mutex_lock中的例子,略。
13.1.7 pthread_mutex_timedlock_np (带超时设置的互斥体锁)
语法:
#include #include int pthread_mutex_timedlock_np(pthread_mutex_t *mutex, const struct timespec *deltatime);
功能:
带超时设置的互斥体的 lock操作。即如果当前互斥体已被别的线程锁住,那么当前线程会阻塞等待,超过指定的时间之后,将会返回一个 EBUSY的返回信息码。参数:
mutex
指定的互斥体
deltatime
指定的超时时长返回: 0 --成功; EBUSY(3029) – 超时退出;其它值 – 其它错误;例子:这个例子中,主线程一直锁住了互斥体,如果直接使用 pthread_mutex_lock操作的话,子线程将会与直等待,而主线程又等待子线程的结束,结果将会造成死锁。所以说,合理使用 pthread_mutex_timedlock_np,以及 pthread_mutex_trylock,可以有效的避免死锁。
#define _MULTI_THREADED
#include
#include
#include
#define checkResults(string, val) { \ if(val){ \ printf("Failed with %d at %s", val, string); \ exit(1); \ }\
}
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *threadFunc(void *parm)
{ int rc; int i; struct timespec deltatime;
deltatime.tv_sec = 5;
deltatime.tv_nsec = 0;
printf("Timed lock the mutex from a secondary thread\n"); rc = pthread_mutex_timedlock_np(&mutex, &deltatime); if (rc != EBUSY) {
printf("Got an incorrect return code from pthread_mutex_timedlock_np\n"); } printf("Thread mutex timeout\n"); return 0;
}
int main(int argc, char **argv)
{ int rc=0; pthread_t thread;
printf("Enter Testcase - %s\n", argv[0]);
printf("Acquire the mutex in the initial thread\n"); rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc);
printf("Create a thread\n"); rc = pthread_create(&thread, NULL, threadFunc, NULL); checkResults("pthread_create()\n", rc);
printf("Join to the thread\n"); rc = pthread_join(thread, NULL); checkResults("pthread_join()\n", rc);
printf("Destroy mutex\n"); pthread_mutex_destroy(&mutex);
printf("Main completed\n"); return 0; }
13.1.8 pthread_mutex_trylock (不进行阻塞处理的互斥体锁)
语法:
#include int pthread_mutex_trylock (pthread_mutex_t *mutex)
功能:这个函数试图锁住一个互斥体,但并不进行阻塞处理。也就是如果执行时,发现该互斥体已被别的线程锁住时,函数将不会阻塞,而是返回一个 EBUSY的错误信息。如果当前线程已锁住这个互斥体时,函数将会返回一个 EDEADLK的错误信息。
参数、返回与函数 pthread_mutex_lock相同,略。例子:这个例子比较具有实用,因为通过 pthread_mutex_lock来控制保护关键数据,造成了对关键数据的操作实质上是处于串行中。
此处通过非阻塞的 pthread_mutex_trylock,充分利用了各个线程自已的资源去进行计算,同时尽可能的实时更改关键数据。最后,计算出各个线程本地计算量的百分比。得出的结果显示大部分计算量都是由各个线程自已完成,程序效率大大提高。
最后输出的参考结果:
Creating 10 threads Wait for results Thread processed about 95% of the problem locally Thread processed about 93% of the problem locally Thread processed about 88% of the problem locally Thread processed about 85% of the problem locally Thread processed about 98% of the problem locally Thread processed about 95% of the problem locally Thread processed about 94% of the problem locally Thread processed about 91% of the problem locally Thread processed about 81% of the problem locally Thread processed about 60% of the problem locally
Cleanup and show results Using 10 threads and LOOPCONSTANT = 100000 Values are: (should be 1000000)
==>1000000, 1000000, 1000000, 1000000 Main completed
#include #include #include #define checkResults(string, val) { \
if(val){ \ printf("Failed with %d at %s", val, string); \ exit(1); \
}\ }
/* This example simulates a number of threads working on a parallel problem. The threads use pthread_mutex_trylock() so that they do not spend time blocking on a mutex and instead spend more of the time making progress towards the final solution. When trylock fails, the processing is done locally, eventually to be merged with the final parallel solution.
This example should complete faster than the example for pthread_mutex_lock() in which threads solve the same parallel problem but spend more time waiting in resource contention. */
#define LOOPCONSTANT 10000 #define THREADS 10
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int i,j,k,l;
void *threadfunc(void *parm)
{ int loop = 0; int localProcessingCompleted = 0; int numberOfLocalProcessingBursts = 0; int processingCompletedThisBurst = 0; int rc;
for (loop=0; loop<LOOPCONSTANT; ++loop) { rc = pthread_mutex_trylock(&mutex); if (rc == EBUSY) {
/* Process continue processing the part of the problem */ /* that we can without the lock. We do not want to waste */ /* time blocking. Instead, we'll count locally. */ ++localProcessingCompleted; ++numberOfLocalProcessingBursts; continue;
} /* We acquired the lock, so this part of the can be global*/ checkResults("pthread_mutex_trylock()\n", rc); /* Processing completed consist of last local processing */ /* plus the 1 unit of processing this time through */ processingCompletedThisBurst = 1 + localProcessingCompleted; localProcessingCompleted = 0; i+=processingCompletedThisBurst; j+=processingCompletedThisBurst; k+=processingCompletedThisBurst; l+=processingCompletedThisBurst;
rc = pthread_mutex_unlock(&mutex);
checkResults("pthread_mutex_unlock()\n", rc); } /* If any local processing remains, merge it with the global*/ /* problem so our part of the solution is accounted for */ if (localProcessingCompleted) {
rc = pthread_mutex_lock(&mutex); checkResults("final pthread_mutex_lock()\n", rc);
i+=localProcessingCompleted; j+=localProcessingCompleted; k+=localProcessingCompleted; l+=localProcessingCompleted;
rc = pthread_mutex_unlock(&mutex);
checkResults("final pthread_mutex_unlock()\n", rc); } printf("Thread processed about %d%% of the problem locally\n",
(numberOfLocalProcessingBursts * 100) / LOOPCONSTANT); return NULL; }
int main(int argc, char **argv)
{ pthread_t threadid[THREADS]; int rc=0; int loop=0; pthread_attr_t pta;
printf("Entering testcase\n");
pthread_attr_init(&pta); pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_JOINABLE);
printf("Creating %d threads\n", THREADS);
for (loop=0; loop<THREADS; ++loop) { rc = pthread_create(&threadid[loop], &pta, threadfunc, NULL); checkResults("pthread_create()\n", rc);
}
printf("Wait for results\n");
for (loop=0; loop%d, %d, %d, %d\n", i, j, k, l);
printf("Main completed\n"); return 0; }
13.2 互斥体属性设置 13.2.1 pthread_mutexattr_init 互斥体属性初始化 13.2.2 pthread_mutexattr_destroy 销毁互斥体属性
Professional Group Tec. Doc.07121901 Author-万一飞
13.2.3 pthread_mutexattr_setkind_np 设置互斥体种类属性 13.2.4 pthread_mutexattr_setname_np 设置互斥体属性名字 13.2.5 pthread_mutexattr_setpshared 设置互斥体中进程属性 13.2.6 pthread_mutexattr_settype 设置互斥体类型属性 13.2.7 pthread_mutexattr_default_np 设置互斥体为默认属性 13.3 取互斥体属性 API – Mutex Attribute API 13.3.1 pthread_mutexattr_getkind_np 取互斥体种类 13.3.2 pthread_mutexattr_getname_np 取互斥体属性目标名 13.3.3 pthread_mutexattr_getpshared 从互斥体中取出进程共享的属性 13.3.4 pthread_mutexattr_gettype 取互斥体类型
14信号量的 API
与信号量相关的 API,其实操作的都是一个信号量组 (semaphore set),或者是一套信号量,总之就是多个信号量的集合。一个信号量组里面,会有多个信号量。
14.1 semget – 带 KEY值取信号量描述符语法:
#include #include
int semget(key_t key, int nsems, int semflg);
功能:
semget这个函数既可以创建一个新的信号量组并返回其描述符,也可以通过 KEY值返回一个已存在的信号量组的描述符。当满足以下任一一个条件时,该函数将会创建新的信号量组:
5、 key参数为 IPC_PRIVATE 6、根据 key参数没有找到已在的信号量组,同时 semflg参数为 IPC_CREAT(此时生成的信号量组即带 key参数)
该函数不会更改已存在的信号量组的状态。当创建新信号量组时,系统将会对 semid_ds结构体中的成员进行如下的初始化赋值: sem_perm.cuid, sem_perm.uid将会赋值为当前线程的用户 ID; sem_perm.guid, sem_perm.gid将会赋值为当前线程的 group ID; sem_perm.mode的低 9位,赋值成为输入参数 semflg的低 9位。
sem_nsems 赋值成为输入参数 nsems sem_ctime赋值成为当前时间 sem_otime赋值为 zero 参数: KEY
输入参数,根据此 KEY查找,或生成信号量组。这个参数为 IPC_PRIVATE(0x00000000)时,此时会生成一个信号量组。用户可以自行指定这个参数,或由函数 ftok()来产生
nsems
输入参数,应该是仅在生成信号量时使用。表明该信号量组中,信号量的数量。当信号量生成之后,这个值不能再更改。如果访问的是一个已存在的信号量,这个值可以赋为 zero..
Semflg 输入参数,操作权限的标识。可以赋值为 zero,或是以下的值: S_IRUSR
允许该信号量的拥有者从中读取数据
S_IWUSR
允许该信号量的拥有者向其中写数据
S_IRGRP
允许该信号量的用户组从中读取数据
S_IWGRP
允许该信号量的用户组向其中写数据
S_IROTH
允许其它用户读取该组信号量
S_IWOTH
允许其它用户向该信号量中写 IPC_CREAT
如果相应 KEY值的信号量不存在,那么建立新的信号量 IPC_EXCL
如果设置了 IPC_CREAT,而信号量已存在时,返回错误
返回: -1 函数发生错误其它值该信号量的唯一标识符
例子:如下面这个不完整的例子中,定义了一个整型变量 semaphoreID,做为信号量的描述符,要赋初始值为-1,即与函数的错误返回相同,以便错误判断处理。这里就创建了一个信号量组,该组中只有一个信号量。
#include #include int semaphoreID = -1 ; semaphoreId = semget(IPC_PRIVATE, 1, S_IRUSR|S_IWUSR);
14.2 semop 对信号量组进行操作语法:
#include
int semop(int semid, struct sembuf *sops, size_t nsops);
功能:对已存在的信号量组执行操作。根据输入的参数,该命令可以对一组信号量中的多个信号量执行操作,也可以对同一信
号量执行多次操作。(可能后者的用法会比较少吧,虽然理论上是可行的)参数:
semid
信号量组的描述符
sops 一个数组的指针,该数组是由一个 sembuf结构的结构体组成。这个结构体用标明
用来具体的操作内容项。
sembuf结构体的定义如下:
struct sembuf { /* sops即是 semaphore operation structure 的简称*/
unsigned short sem_num; /* 信号量组中,要操作的信号量的编号(位置) */
short sem_op; /* 操作数值 */
short sem_flg; /*操作标志 SEM_UNDO and IPC_NOWAIT */
}
该数组中,一条记录(即一个结构体),就标识了一次操作。如果有多条记录(多个结构体),那么可以执行多次操作。结构体中的 sem_num变量标识的是信号量组中,指定的信号量的编号,由 0开始。即该组信号量中,第一个信号量的编号为 0,第二个信号量为 1。
Nsops
上述数组中的记录个数(即结构体的个数),也就是要执行的操作次数。返回:
0操作成功
非 0 操作失败注意事项:
系统根据入口参数中的 sops,逐笔对信号量执行操作直至完毕。当执行 sem_op操作时,其它的线程都不能再操作这个信号量组,直到当前线程结束操作,或被挂起。
如果结构体中的 sem_op参数是正数,函数将会增加指定的信号量的数值,然后唤起相应数量的?重新运行条件为信号量增加而的线程,这也就相当于通过信号量释放资源。如果结构体中的 sem_op参数是负数,函数将会减去指定的信号量的数值。当结果为负数的时候,线程将会挂起,直到该信号量增加;(即当前线程重新运行
条件为指定的信号量增加)
如果结果是正数,就仅仅只是减去信号量的数值而已;
如果结果是 0,将会唤起相应数量的?重新运行条件为信号量数值等于 0的线程。
如果结构体中的 sem_op的参数为 0,就表示挂起当前线程,直到指定的信号量数值为
0. 如果 sem_flg参数设置为 IPC_NOWAIT,那么当前线程不能运行时,将不会被挂起,而是直接返回 EAGAIN的错误码。
如果 sem_flg参数设置为 SEM_UNDO,那么当线程结束时,对指定信号量的操作将会回滚,也就是通过信号量来控制资源的回收与申请。
如果 sem_flg参数设置为 0,就表示只进行标准处理,没有其它特殊操作。
当使用 sem_op操作挂起线程的时候,这个线程可以被其它的线程中断。
例子:
在下面这个例子里,先生成了一个信号量组,这个组里只有一个信号量。然后对这个信号量进行操作。
LockOperation就是一个 sembuf结构的变量,
第一位 0.,表示操作信号量组中的第一个信号量;
第二位 -1,表示对信号量进行减操作;
第三位 0,表示没有特殊处理
在执行 semop函数时,首位参数 semaporeId,表示信号量组的描述符;第二位参数传递的是 lockOperation地址第三位参数 1,表示第二位参数传递的内容中,只含一次操作的内容。
#include #include int rc; int semaphoreID = -1 ; struct sembuf lockOperation = { 0, -1, 0}; semaphoreId = semget(IPC_PRIVATE, 1, S_IRUSR|S_IWUSR); rc = semop(semaphoreId, &lockOperation, 1);
14.3 semctl --对信号量进行控制操作语法:
#include int semctl(int semid, int semnum, int cmd, 可选参数);
功能:
这个函数允许调用者控制指定的信号量。
调用者通过 cmd参数,来表达需要进行控制的内容:
IPC_RMID(0x00000000)从系统中移除信号量组描述符,销毁信号量组。所有执行 sem_op操作后,基于这个信号量组而挂起的线程,将会返回一个-1,同时错误码为 EIDRM
IPC_SET(0x00000001)通过第 4个可选参数,设置 semid_ds数据结构中的 sem_perm.uid,sem_perm.gid, sem_perm.mode的值。这里,第 4个参数此时是一个指向 semid_ds类型结构体的指针。
IPC_STAT(0x00000002)通过第 4个可选参数,保存 semid_ds数据结构中的当前值。第 4个参数此时是一个指向 semid_ds类型结构体的指针。
GETNCNT(0x00000003)返回唤起条件为“指定的信号量数值增加”的线程数量。这个数值对应 semaphore_t 结构中的 semncnt。
GETPID (0x00000004) 返回最后一个操作指定信号量的线程所属的进程 ID。这个数值对应 semaphore_t 结构中的 sempid.
GETVAL(0x00000005) 返回指定的信号量的当前数值。这个数值对应 semaphore_t结构中的 semval.
GETALL(0x00000006)通过第四个可选参数,返回这个信号量组中,所有信号量当前的值。这个参数此时是一个数组指针,数组中元素类型为 unsigned short.
GETZCNT(0x00000007)返回唤起条件为“指定的信号量数值等于 0”的线程数量。这个数值对应 smeaphore_t 结构中的 semzcnt.
SETVAL(0x00000008)
将指定的信号量的数值赋值为第 4个可选参数,此时该参数类型需要为 int.同时清除与信号量有关联的每个线程的信号量调整值(Set the value of semaphore semnum to the integer value of type int specified in the fourth parameter and clear the associated per-thread semaphore adjustment value.)
SETALL(0x00000009)
通过第 4个可选参数,将信号量组中的每一个信号量的值都进行相应更改。此时第 4个参数是一个数组指针,数组中元素类型为 unsigned short.同时,与每个信号量有关联的线程,都会清除其信号量调整值。( In addition, the associated per-thread semaphore-adjustment value is cleared for each semaphore)
参数:
semid
输入参数,正整数,信号量组描述符。
Semnum 输入参数,非负整数。标识指定信号量在信号量组中的编号。编号从 0开始,即该组信号量中,第一个信号量的编号为 0,第二个信号量的编号为 1.
Cmd
控制符,见上文中的描述。
可选参数根据具体情况而定,有时表示输入,有时表示输出。有时是一个整型变量,有时是一个数组指针,详情见上文中的描述。返回:当返回成功时,视 cmd参数的不同,会有不同的返回值
GETVAL返回信号量的数值 GETPID 返回进程号 GETNCNT返回符合条件的线程数量 GETZCNT 返回符合条件的线程数量其它操作返回 0
当函数失败时,返回-1
例子:下面这个简单的例子中,接上面 semop操作的内容,对信号量组进行了 SETVAL的控制操作,将这个信号量组中的第一个信号量的数值设置为 1.
#include #include int rc; int semaphoreID = -1 ; struct sembuf lockOperation = { 0, -1, 0}; semaphoreId = semget(IPC_PRIVATE, 1, S_IRUSR|S_IWUSR); rc = semop(semaphoreId, &lockOperation, 1);
rc = semctl(semaphoreId, 0, SETVAL, (int)1);
15其它
15.1 spawn 语法: #include pid_t spawn( const char *path, const int fd_count, const int fd_map[], const struct inheritance *inherit, char * const argv[], char * const envp[]); 功能:
参数:
path
输入参数,可执行文件名。
Fd_count
输入参数,子进程可以继承的文件描述符
fd_map[]
输入参数,子进程接收到当前进程传递给它的文件描述符数组
inherit 输入参数,一个 inheritance类型的结构的地址。返回:
例子:
下面这个例子演示了通过 spawn函数,创建一个进程,新的进程继承了当前进程的 socket 描述符。 /**************************************************************************/ /* Application creates an child process using spawn(). */ /**************************************************************************/
#include #include #include #include #include
#define SERVER_PORT 12345
main (int argc, char *argv[])
{ int i, num, pid, rc, on = 1; int listen_sd, accept_sd; int spawn_fdmap[1]; char *spawn_argv[1]; char *spawn_envp[1];
struct inheritance inherit; struct sockaddr_in addr;
/*************************************************/ /* If an argument was specified, use it to */ /* control the number of incoming connections */ /*************************************************/ if (argc >= 2)
num = atoi(argv[1]); else num= 1;
/*************************************************/ /* Create an AF_INET stream socket to receive */ /* incoming connections on */ /*************************************************/ listen_sd = socket(AF_INET, SOCK_STREAM, 0); if (listen_sd < 0) {
perror("socket() failed"); exit(-1); }
/*************************************************/ /* Allow socket descriptor to be reuseable */ /*************************************************/ rc = setsockopt(listen_sd,
SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on)); if (rc < 0) {
perror("setsockopt() failed"); close(listen_sd); exit(-1);
}
/*************************************************/ /* Bind the socket */ /*************************************************/ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(SERVER_PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); rc = bind(listen_sd,
(struct sockaddr *)&addr, sizeof(addr)); if (rc < 0) {
perror("bind() failed"); close(listen_sd); exit(-1);
}
/*************************************************/ /* Set the listen back log */ /*************************************************/ rc = listen(listen_sd, 5); if (rc < 0) {
perror("listen() failed"); close(listen_sd); exit(-1);
}
/*************************************************/ /* Inform the user that the server is ready */ /*************************************************/ printf("The server is ready\n");
/*************************************************/ /* Go through the loop once for each connection */ /*************************************************/ for (i=0; i < num; i++) {
/**********************************************/ /* Wait for an incoming connection */ /**********************************************/ printf("Interation: %d\n", i+1); printf(" waiting on accept()\n"); accept_sd = accept(listen_sd, NULL, NULL); if (accept_sd < 0) {
perror("accept() failed"); close(listen_sd); exit(-1);
} printf(" accept completed successfully\n");
/**********************************************/ /* Initialize the spawn parameters */ /* */
/* The socket descriptor for the new */ /* connection is mapped over to descriptor 0 */ /* in the child program. */ /**********************************************/ memset(&inherit, 0, sizeof(inherit)); spawn_argv[0] = NULL; spawn_envp[0] = NULL; spawn_fdmap[0] = accept_sd;
/**********************************************/ /* Create the worker job */ /**********************************************/ printf(" creating worker job\n"); pid = spawn("/QSYS.LIB/QGPL.LIB/WRKR1.PGM",
1, spawn_fdmap, &inherit,
spawn_argv, spawn_envp); if (pid < 0) {
perror("spawn() failed"); close(listen_sd); close(accept_sd);
exit(-1); } printf(" spawn completed successfully\n");
/**********************************************/ /* Close down the incoming connection since */ /* it has been given to a worker to handle */ /**********************************************/ close(accept_sd);
}
/*************************************************/ /* Close down the listen socket */ /*************************************************/ close(listen_sd);
} |