最近很多小伙伴都在问IPC研究和4----semaphores这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展c#–SkipSemaphoreSlim而不是等待、c#–具有动态ma
最近很多小伙伴都在问IPC研究和4 ---- semaphores这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展c# – Skip SemaphoreSlim而不是等待、c# – 具有动态maxCount的SemaphoreSlim、c#并发semaphoreslim、C/C++ 信号量 CreateSemaphore 用法等相关知识,下面开始了哦!
本文目录一览:- IPC研究(4) ---- semaphores(IPC研究所)
- c# – Skip SemaphoreSlim而不是等待
- c# – 具有动态maxCount的SemaphoreSlim
- c#并发semaphoreslim
- C/C++ 信号量 CreateSemaphore 用法
IPC研究(4) ---- semaphores(IPC研究所)
============================================================IPC --- System V IPC --- semaphores
Related System Calls:
[designed to work for arrays of semaphore values]
#include <sys/sem.h>
semctl
semget
semop
Basics:
Purpose: provide the feature for a single process to have exclusive access to a resource
Application scenes: multi-threaded programs, multiprocess programs or a combine of the two
General definition: two operations -- P(wait) and V(signal)
=> binaray semaphore (0,1)
=> general semaphore (0,1,2,...)
和file类似,不同的进程会有不同的semaphore identifier,但是,它们都指向同一个semaphore。(就像fd和inode)
对于file,不同的进程用filename来得到file descriptors,对于semaphore,不同的进程用key来得到不同的semaphore identifiers。
用semaphore通信的各个进程间,需要有个共同的key。
Analysis:
1. Linux Kernel是如何支持semaphore通信机制的呢?
struct_task结构中有相应的semaphore的域,如果systemV IPC支持被编译进来,就可以支持。
2. semaphore主要是用来解决资源访问冲突的问题的。对于资源访问的竞争问题,有如下模型:
process1 |
process2 | <==> RESOURCE
process3 |
要使访问资源不因为出现竞争状态而出现不想要的结果,有两种方法。
第一,在resource侧做控制,组织多个进程同时访问,或者对将访问block。比如file lock
第二,在访问的process间做控制,使得他们能够互相通信,从而解决访问冲突。
在Linux中,第二种解决方案,就是semaphore。
Examples:
#ifndef _JAMES_C_SEMAPHORE_H
#define _JAMES_C_SEMAPHORE_H
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun
{
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* array for GETALL SETALL */
struct seminfo __buf; /* buffer for IPC_INFO (Linux-specific) */
};
int set_semvalue(int sem_id);
void del_semvalue(int sem_id);
int semaphore_p(int sem_id);
int semaphore_v(int sem_id);
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "mysem.h"
int set_semvalue(int sem_id)
{
union semun sem_union;
sem_union.val = 1;
if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
return -1;
return 0;
}
void del_semvalue(int sem_id)
{
union semun sem_union;
if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
perror("Failed to delete semaphore");
}
int semaphore_p(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1; /* *P() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed\n");
return -1;
}
return 0;
}
int semaphore_v(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_v failed\n");
return -1;
}
return 0;
}
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "mysem.h"
int main(int argc, char *argv[])
{
int sem_id;
int i;
int pause_time;
char op_char;
srand( (unsigned int)getpid() );
op_char = ''a'' + rand()%26; /* other process */
sem_id = semget( (key_t)1234, 1, 0666 | IPC_CREAT);
if (argc > 1)
{
if ( set_semvalue(sem_id) < 0)
{
fprintf(stderr, "Failed to initialize semaphore\n");
exit(-1);
}
op_char = ''X''; /* creation process */
sleep(2);
}
for (i=0; i<5; i++)
{
if (semaphore_p(sem_id) < 0)
exit(-1);
printf("%c", op_char); fflush(stdout);
pause_time = rand()%3;
sleep(pause_time);
printf("%c", op_char); fflush(stdout);
if (semaphore_v(sem_id) < 0)
exit(-1);
sleep(pause_time);
}
printf("\n%d - finished\n", getpid());
if (argc > 1)
{
sleep(10);
del_semvalue(sem_id);
}
return 0;
}
c# – Skip SemaphoreSlim而不是等待
通过创建新的SemaphoreSlim(1)并使用WaitAsync / Release,这相对简单.结果是第一个线程执行而其他线程等待然后逐个执行.
我想要实现的目标实际上略有不同.我希望其他线程不要等待,但要退出该函数(即我不想阻止其他线程).因此,如果有一个属性“NumberOfThreadsCurrentlyExecuting”,我将有效地拥有一个If Semaphore.NumberOfThreadsCurrentlyExecuting> 0然后返回.
但这样的财产不存在.有没有人知道解决这个问题的方法?
谢谢
查尔斯
解决方法
如果您调用TryEnter
并且它失败,则另一个线程处于“锁定”状态.
这是线程安全的(与检查信号量计数不同),相当简单:
//使用somethign如:object sync = new object();
bool lockTaken = Monitor.TryEnter(sync); try { if (lockTaken) { // You're here - do your work } else { // Something else was in the thread - exit? return; } } finally { if (lockTaken) Monitor.Exit(sync); }
c# – 具有动态maxCount的SemaphoreSlim
我在考虑使用SemaphoreSlim类,但是没有公共属性来更改最大计数.
我应该将我的SemaphoreSlim类包装在另一个将处理最大计数的类中吗?有没有更好的方法?
编辑:
这是我正在尝试的:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Semaphore { class Program { static SemaphoreSlim _sem = new SemaphoreSlim(10,10000); static void Main(string[] args) { int max = 15; for (int i = 1; i <= 50; i++) { new Thread(Enter).Start(new int[] { i,max}); } Console.ReadLine(); max = 11; for (int i = 1; i <= 50; i++) { new Thread(Enter).Start(new int[] { i,max }); } } static void Enter(object param) { int[] arr = (int[])param; int id = arr[0]; int max = arr[1]; try { Console.WriteLine(_sem.CurrentCount); if (_sem.CurrentCount <= max) _sem.Release(1); else { _sem.Wait(1000); Console.WriteLine(id + " wants to enter"); Thread.Sleep((1000 * id) / 2); // can be here at Console.WriteLine(id + " is in!"); // Only three threads } } catch(Exception ex) { Console.WriteLine("opps ",id); Console.WriteLine(ex.Message); } finally { _sem.Release(); } } } }
问题:
1-_sem.Wait(1000)应该取消执行超过1000ms的线程,不是吗?
2 – 我是否有使用发布/等待的想法?
解决方法
所以我们假设绝对最大并发调用数是100,但最初你希望它是25.你初始化你的信号量:
SemaphoreSlim sem = new SemaphoreSlim(25,100);
因此25是可以同时服务的请求数.你保留了其他75.
如果您想增加允许的数量,只需调用Release(num).如果您调用了Release(10),那么该数字将变为35.
现在,如果要减少可用请求的数量,则必须多次调用WaitOne.例如,如果要从可用计数中删除10:
for (var i = 0; i < 10; ++i) { sem.WaitOne(); }
这有可能阻塞,直到其他客户端释放信号量.也就是说,如果您允许35个并发请求,并且您希望将其减少到25,但是已经有35个客户端具有活动请求,那么WaitOne将阻塞,直到客户端调用Release,并且循环将不会终止,直到10个客户端发布.
c#并发semaphoreslim
该类限制了用时访问同一资源的线程数量,下面写一段代码来讲解他的用法
class Program
{
static SemaphoreSlim _semaphore = new SemaphoreSlim(4);
static void acquireSemaphore(string name, int seconds)
{
Console.WriteLine("{0} wait",name);
_semaphore.Wait();
Console.WriteLine("{0} access",name);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("{0} Release", name);
_semaphore.Release();
}
static void Main(string[] args)
{
for(int i = 1; i <= 6; i++)
{
string threadName = "thread" + i;
int secondsToWait = 2 + 2 * i;
var t = new Thread(() => acquireSemaphore(threadName, secondsToWait));
t.Start();
}
Console.ReadKey();
这里我写了一个函数来获取SemaphoreSlim 信号量,在创建时static SemaphoreSlim _semaphore = new SemaphoreSlim(4);设置可以同时访问的线程数为4,也就是说运行后的情况应该是在线程1、2、3、4访问该信号量没有释放之前,线程5会一直处于等待状态,下面我们运行一下看看结果。
从运行结果我们可以看到,线程5,6处于等待状态,直到1释放5获得信号量,2释放6获得信号量。
---------------------
作者:Maybe_ch
来源:CSDN
原文:https://blog.csdn.net/Maybe_ch/article/details/84818373
版权声明:本文为博主原创文章,转载请附上博文链接!
C/C++ 信号量 CreateSemaphore 用法
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD
LONG lInitialCount, // initial count
LONG lMaximumCount, // maximum count
LPCTSTR lpName // object name
)
此函数可用来创建或打开一个信号量,先看参数说明:
lpSemaphoreAttributes:为信号量的属性,一般可以设置为NULL
lInitialCount:信号量初始值,必须大于等于0,而且小于等于 lpMaximumCount,如果lInitialCount 的初始值为0,则该信号量默认为unsignal状态,如果lInitialCount的初始值大于0,则该信号量默认为signal状态,
lMaximumCount: 此值为设置信号量的最大值,必须大于0
lpName:信号量的名字,长度不能超出MAX_PATH ,可设置为NULL,表示无名的信号量。当lpName不为空时,可创建有名的信号量,若当前信号量名与已存在的信号量的名字相同时,则该函数表示打开该信号量,这时参数lInitialCount 和
lMaximumCount 将被忽略。
函数调用成功返回信号量句柄。
释放信号量函数:
BOOL ReleaseSemaphore( HANDLE hSemaphore, // handle to semaphore
LONG lReleaseCount, // count increment amount
LPLONG lpPreviousCount // previous count);
参数说明:
hSemaphore:信号量句柄,
lReleaseCount:释放的数量,一般完成一个等待后调用此函数释放一个信号量,使得信号量平衡。
lpPreviousCount :存放以前信号量的数量 ,一般可为NULL.
打开信号量函数:
HANDLE OpenSemaphore(
DWORD dwDesiredAccess, // access
BOOL bInheritHandle, // inheritance option
LPCTSTR lpName// object name
);
此函数打开一个有名的信号量
参数说明:
dwDesiredAccess:对信号量的访问权限,取值可以是SEMAPHORE_ALL_ACCESS,可对信号量执行尽可能多的操作;可以是SEMAPHORE_MODIFY_STATE,允许使用ReleaseSemaphore释放信号量,达到修改信号量;还可以是SYNCHRONIZE,用等待函数异步的等待信号量变为signal状态
bInheritHandle:如果为true,信号量句柄可被继承,反之不可继承。
lpName :信号量的名字。
别忘了最后使用完成后用CloseHandle()关闭信号量句柄
暂时API写到此为止,以后还有关信号量的函数,再继续添加。下面通过一个例子,来说明使用信号量来世线程同步的例子,要求创建三个线程,每个线程次打印十次ID,必须三个线程一次打印。注意:在使用WaitForSingleObject等待信号量句柄时,若信号量为signal状态,则wait过后信号量自动减1,直到使用ReleaseSemaphore释放信号量,信号量才可增加
代码如下:
说明:创建控制台程序。
#include "stdafx.h"
#include <Windows.h>
DWORD WINAPI Thread_1(LPVOID param);
DWORD WINAPI Thread_2(LPVOID param);
DWORD WINAPI Thread_3(LPVOID param);
HANDLE hSM_1;
HANDLE hSM_2;
HANDLE hSM_3;
HANDLE hThread_1;
HANDLE hThread_2;
HANDLE hThread_3;
int _tmain(int argc, _TCHAR* argv[])
{
//创建三个信号量
hSM_1 = CreateSemaphore(NULL, 1, 1, L"A");//开始为signal状态
hSM_2 = CreateSemaphore(NULL, 0, 1, L"B");//开始为unsignal状态,等待hSM_1释放
hSM_3 = CreateSemaphore(NULL, 0, 1, L"C");//开始为unsignal状态,等待hSM_2
//创建三个线程
hThread_1 = CreateThread(NULL, 0, Thread_1, NULL, 0, NULL);
hThread_2 = CreateThread(NULL, 0, Thread_2, NULL, 0, NULL);
hThread_3 = CreateThread(NULL, 0, Thread_3, NULL, 0, NULL);
//等待三个线程都执行完
WaitForSingleObject(hThread_1, INFINITE);
WaitForSingleObject(hThread_2, INFINITE);
WaitForSingleObject(hThread_3, INFINITE);
//三个线程都执行完
printf("\n\n\t main end \n");
//关闭句柄
CloseHandle(hThread_1);
CloseHandle(hThread_2);
CloseHandle(hThread_3);
CloseHandle(hSM_1);
CloseHandle(hSM_2);
CloseHandle(hSM_3);
return 0;
}
DWORD WINAPI Thread_1(LPVOID param)
{
for (int i = 0; i < 10; i ++)
{
DWORD dwWait = WaitForSingleObject(hSM_1, INFINITE);
//每一个wait过后信号量的数量自动减1,这样就达到了控制同步
printf("A");
ReleaseSemaphore(hSM_2, 1, NULL);
}
return 0;
}
DWORD WINAPI Thread_2(LPVOID param)
{
for (int i = 0; i < 10; i ++)
{
WaitForSingleObject(hSM_2, INFINITE);
printf("B");
ReleaseSemaphore(hSM_3, 1, NULL);
}
return 0;
}
DWORD WINAPI Thread_3(LPVOID param)
{
for (int i = 0; i < 10; i ++)
{
WaitForSingleObject(hSM_3, INFINITE);
printf("C ");
ReleaseSemaphore(hSM_1, 1, NULL);
}
return 0;
}

我们今天的关于IPC研究和4 ---- semaphores的分享已经告一段落,感谢您的关注,如果您想了解更多关于c# – Skip SemaphoreSlim而不是等待、c# – 具有动态maxCount的SemaphoreSlim、c#并发semaphoreslim、C/C++ 信号量 CreateSemaphore 用法的相关信息,请在本站查询。
本文标签: